diff --git a/SUPPORTED b/SUPPORTED
index a4bf79c6a6e6401b47a9711f91db0960cb295c72..fdf15fddf5178319f10d8517287b57f1b743f942 100644
--- a/SUPPORTED
+++ b/SUPPORTED
@@ -159,7 +159,8 @@ en_SG/ISO-8859-1 \
en_US.UTF-8/UTF-8 \
en_US/ISO-8859-1 \
en_US.ISO-8859-15/ISO-8859-15 \
-en_US@ampm.UTF-8/UTF-8 \
+en_US@ampm/UTF-8 \
+en_US.UTF-8@ampm/UTF-8 \
en_ZA.UTF-8/UTF-8 \
en_ZA/ISO-8859-1 \
en_ZM/UTF-8 \
diff --git a/build-locale-archive.c b/build-locale-archive.c
index 9183972375dbd1e4239fc52c955d1c210de60d42..3cb3b47580512be731be9497a5a23a06ce8f2bf6 100644
--- a/build-locale-archive.c
+++ b/build-locale-archive.c
@@ -448,7 +448,7 @@ fill_archive (struct locarhandle *tmpl_ah,
char fullname[fnamelen + 2 * strlen (d->d_name) + 7];
#ifdef _DIRENT_HAVE_D_TYPE
- if (d_type == DT_UNKNOWN)
+ if (d_type == DT_UNKNOWN || d_type == DT_LNK)
#endif
{
strcpy (stpcpy (stpcpy (fullname, fname), "/"),
diff --git a/dist b/dist
new file mode 100644
index 0000000000000000000000000000000000000000..9c0e36ec42a2d9bfefacb21ac6354c9ddd910533
--- /dev/null
+++ b/dist
@@ -0,0 +1 @@
+an8
diff --git a/glibc-Add-a-testcase-to-check-alignment-of-PT_LOAD-segment-2.patch b/glibc-Add-a-testcase-to-check-alignment-of-PT_LOAD-segment-2.patch
index 8fbe86d9a4c1f893e07907140a410393e6617d94..5ffa33938a24bd1769409507e0594bfe13aa03d1 100644
--- a/glibc-Add-a-testcase-to-check-alignment-of-PT_LOAD-segment-2.patch
+++ b/glibc-Add-a-testcase-to-check-alignment-of-PT_LOAD-segment-2.patch
@@ -19,35 +19,34 @@ diff --git a/elf/Makefile b/elf/Makefile
index 2093cefa..0d3366e2 100644
--- a/elf/Makefile
+++ b/elf/Makefile
-@@ -187,7 +187,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
- tst-tls4 tst-tls5 \
- tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
- tst-tls16 tst-tls17 tst-tls18 tst-tls19 tst-tls-dlinfo \
-- tst-align tst-align2 \
-+ tst-align tst-align2 tst-align3 \
- tst-dlmodcount tst-dlopenrpath tst-deep1 \
- tst-dlmopen1 tst-dlmopen3 \
- unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
-@@ -221,6 +221,9 @@ tests += tst-dlopen-aout
- tst-dlopen-aout-no-pie = yes
- endif
- test-srcs = tst-pathopt
+@@ -331,6 +331,7 @@ tests += \
+ tst-addr1 \
+ tst-align \
+ tst-align2 \
++ tst-align3 \
+ tst-audit1 \
+ tst-audit11 \
+ tst-audit12 \
+@@ -463,7 +464,9 @@ endif
+ test-srcs = \
+ tst-pathopt
+ # tests-srcs
+-
+ifeq (yes,$(have-fpie))
+tests-pie += tst-align3
+endif
selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
+
ifneq ($(selinux-enabled),1)
- tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
-@@ -268,7 +271,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
- circlemod3 circlemod3a \
- reldep8mod1 reldep8mod2 reldep8mod3 \
- reldep9mod1 reldep9mod2 reldep9mod3 \
-- tst-alignmod tst-alignmod2 \
-+ tst-alignmod tst-alignmod2 tst-alignmod3 \
- $(modules-execstack-$(have-z-execstack)) \
- tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
- tst-dlmopen1mod tst-auditmod1 \
-@@ -1060,6 +1063,13 @@ CFLAGS-tst-alignmod2.c += $(stack-align-test-flags)
+@@ -605,6 +608,7 @@ modules-names = \
+ tst-absolute-zero-lib \
+ tst-alignmod \
+ tst-alignmod2 \
++ tst-alignmod3 \
+ tst-array2dep \
+ tst-array5dep \
+ tst-audit11mod1 \
+@@ -1602,6 +1606,13 @@ CFLAGS-tst-alignmod2.c += $(stack-align-
$(objpfx)tst-align: $(libdl)
$(objpfx)tst-align.out: $(objpfx)tst-alignmod.so
$(objpfx)tst-align2: $(objpfx)tst-alignmod2.so
@@ -58,7 +57,7 @@ index 2093cefa..0d3366e2 100644
+LDFLAGS-tst-align3 += -Wl,-z,max-page-size=0x200000
+LDFLAGS-tst-alignmod3.so += -Wl,-z,max-page-size=0x200000
+$(objpfx)tst-alignmod3.so: $(libsupport)
-
+
$(objpfx)unload3: $(libdl)
$(objpfx)unload3.out: $(objpfx)unload3mod1.so $(objpfx)unload3mod2.so \
diff --git a/elf/tst-align3.c b/elf/tst-align3.c
@@ -66,7 +65,7 @@ new file mode 100644
index 00000000..ac86d623
--- /dev/null
+++ b/elf/tst-align3.c
-@@ -0,0 +1,38 @@
+@@ -0,0 +1,37 @@
+/* Check alignment of PT_LOAD segment in a shared library.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
@@ -86,7 +85,6 @@ index 00000000..ac86d623
+ . */
+
+#include
-+#include
+
+/* This should cover all possible page sizes we currently support. */
+#define ALIGN 0x200000
@@ -110,7 +108,7 @@ new file mode 100644
index 00000000..0d33f237
--- /dev/null
+++ b/elf/tst-alignmod3.c
-@@ -0,0 +1,32 @@
+@@ -0,0 +1,31 @@
+/* Check alignment of PT_LOAD segment in a shared library.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
@@ -130,7 +128,6 @@ index 00000000..0d33f237
+ . */
+
+#include
-+#include
+
+/* This should cover all possible page sizes we currently support. */
+#define ALIGN 0x200000
diff --git a/glibc-Support-target-specific-ALIGN-for-variable-alignment-4.patch b/glibc-Support-target-specific-ALIGN-for-variable-alignment-4.patch
index 5ac20550685952363383938f7aa0fb3d5b17bb13..0b37ef01de4f62dece870606c5d53fa83caa1b28 100644
--- a/glibc-Support-target-specific-ALIGN-for-variable-alignment-4.patch
+++ b/glibc-Support-target-specific-ALIGN-for-variable-alignment-4.patch
@@ -32,36 +32,32 @@ diff --git a/elf/tst-align3.c b/elf/tst-align3.c
index ac86d623..87a8ff81 100644
--- a/elf/tst-align3.c
+++ b/elf/tst-align3.c
-@@ -17,11 +17,9 @@
+@@ -17,9 +17,7 @@
. */
-
+
#include
-+#include
- #include
-
+-
-/* This should cover all possible page sizes we currently support. */
-#define ALIGN 0x200000
--
++#include
+
int bar __attribute__ ((aligned (ALIGN))) = 1;
- extern int do_load_test (void);
diff --git a/elf/tst-alignmod3.c b/elf/tst-alignmod3.c
index 0d33f237..9520c352 100644
--- a/elf/tst-alignmod3.c
+++ b/elf/tst-alignmod3.c
-@@ -17,11 +17,9 @@
+@@ -17,9 +17,7 @@
. */
-
+
#include
-+#include
- #include
-
+-
-/* This should cover all possible page sizes we currently support. */
-#define ALIGN 0x200000
--
++#include
+
int foo __attribute__ ((aligned (ALIGN))) = 1;
-
- void
+
diff --git a/sysdeps/alpha/tst-file-align.h b/sysdeps/alpha/tst-file-align.h
new file mode 100644
index 00000000..8fc3c940
diff --git a/glibc-rh1888660.patch b/glibc-rh1888660.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ec80b81a68154090e2842bbb8f91ce7bde9f2ba0
--- /dev/null
+++ b/glibc-rh1888660.patch
@@ -0,0 +1,767 @@
+This patch is a RHEL-8.7 backport of the following upstream commit:
+
+commit 52a103e237329b9f88a28513fe7506ffc3bd8ced
+Author: Arjun Shankar
+Date: Tue May 24 17:57:36 2022 +0200
+
+ Fix deadlock when pthread_atfork handler calls pthread_atfork or dlclose
+
+ In multi-threaded programs, registering via pthread_atfork,
+ de-registering implicitly via dlclose, or running pthread_atfork
+ handlers during fork was protected by an internal lock. This meant
+ that a pthread_atfork handler attempting to register another handler or
+ dlclose a dynamically loaded library would lead to a deadlock.
+
+ This commit fixes the deadlock in the following way:
+
+ During the execution of handlers at fork time, the atfork lock is
+ released prior to the execution of each handler and taken again upon its
+ return. Any handler registrations or de-registrations that occurred
+ during the execution of the handler are accounted for before proceeding
+ with further handler execution.
+
+ If a handler that hasn't been executed yet gets de-registered by another
+ handler during fork, it will not be executed. If a handler gets
+ registered by another handler during fork, it will not be executed
+ during that particular fork.
+
+ The possibility that handlers may now be registered or deregistered
+ during handler execution means that identifying the next handler to be
+ run after a given handler may register/de-register others requires some
+ bookkeeping. The fork_handler struct has an additional field, 'id',
+ which is assigned sequentially during registration. Thus, handlers are
+ executed in ascending order of 'id' during 'prepare', and descending
+ order of 'id' during parent/child handler execution after the fork.
+
+ Two tests are included:
+
+ * tst-atfork3: Adhemerval Zanella
+ This test exercises calling dlclose from prepare, parent, and child
+ handlers.
+
+ * tst-atfork4: This test exercises calling pthread_atfork and dlclose
+ from the prepare handler.
+
+ [BZ #24595, BZ #27054]
+
+ Co-authored-by: Adhemerval Zanella
+ Reviewed-by: Adhemerval Zanella
+
+diff --git a/nptl/Makefile b/nptl/Makefile
+index 70a3be23ecfcd9c9..76c914e23e8873f2 100644
+--- a/nptl/Makefile
++++ b/nptl/Makefile
+@@ -382,8 +382,17 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
+ tst-cancelx16 tst-cancelx17 tst-cancelx18 tst-cancelx20 tst-cancelx21 \
+ tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4
+ ifeq ($(build-shared),yes)
+-tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder \
+- tst-audit-threads
++tests += \
++ tst-atfork2 \
++ tst-tls4 \
++ tst-_res1 \
++ tst-fini1 \
++ tst-compat-forwarder \
++ tst-audit-threads \
++ tst-atfork3 \
++ tst-atfork4 \
++# tests
++
+ tests-internal += tst-tls3 tst-tls3-malloc tst-tls5 tst-stackguard1
+ tests-nolibpthread += tst-fini1
+ ifeq ($(have-z-execstack),yes)
+@@ -391,18 +400,39 @@ tests += tst-execstack
+ endif
+ endif
+
+-modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
+- tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \
+- tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \
+- tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod \
+- tst-join7mod tst-compat-forwarder-mod tst-audit-threads-mod1 \
+- tst-audit-threads-mod2
++modules-names = \
++ tst-atfork2mod \
++ tst-tls3mod \
++ tst-tls4moda \
++ tst-tls4modb \
++ tst-tls5mod \
++ tst-tls5moda \
++ tst-tls5modb \
++ tst-tls5modc \
++ tst-tls5modd \
++ tst-tls5mode \
++ tst-tls5modf \
++ tst-stack4mod \
++ tst-_res1mod1 \
++ tst-_res1mod2 \
++ tst-execstack-mod \
++ tst-fini1mod \
++ tst-join7mod \
++ tst-compat-forwarder-mod \
++ tst-audit-threads-mod1 \
++ tst-audit-threads-mod2 \
++ tst-atfork3mod \
++ tst-atfork4mod \
++# module-names
++
+ extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) \
+ tst-cleanup4aux.o tst-cleanupx4aux.o
+ test-extras += tst-cleanup4aux tst-cleanupx4aux
+ test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
+
+ tst-atfork2mod.so-no-z-defs = yes
++tst-atfork3mod.so-no-z-defs = yes
++tst-atfork4mod.so-no-z-defs = yes
+ tst-tls3mod.so-no-z-defs = yes
+ tst-tls5mod.so-no-z-defs = yes
+ tst-tls5moda.so-no-z-defs = yes
+@@ -541,6 +571,14 @@ LDFLAGS-tst-atfork2 = -rdynamic
+ tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace
+ $(objpfx)tst-atfork2mod.so: $(shared-thread-library)
+
++$(objpfx)tst-atfork3: $(libdl) $(shared-thread-library)
++LDFLAGS-tst-atfork3 = -rdynamic
++$(objpfx)tst-atfork3mod.so: $(shared-thread-library)
++
++$(objpfx)tst-atfork4: $(libdl) $(shared-thread-library)
++LDFLAGS-tst-atfork4 = -rdynamic
++$(objpfx)tst-atfork4mod.so: $(shared-thread-library)
++
+ tst-stack3-ENV = MALLOC_TRACE=$(objpfx)tst-stack3.mtrace
+ $(objpfx)tst-stack3-mem.out: $(objpfx)tst-stack3.out
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@; \
+@@ -640,6 +678,8 @@ $(objpfx)../libc.so: $(common-objpfx)libc.so ;
+ $(addprefix $(objpfx),$(tests-static) $(xtests-static)): $(objpfx)libpthread.a
+
+ $(objpfx)tst-atfork2.out: $(objpfx)tst-atfork2mod.so
++$(objpfx)tst-atfork3.out: $(objpfx)tst-atfork3mod.so
++$(objpfx)tst-atfork4.out: $(objpfx)tst-atfork4mod.so
+ else
+ $(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a
+ endif
+diff --git a/nptl/register-atfork.c b/nptl/register-atfork.c
+index 9edb7d4bbb49fbed..4c1e20ae8cab005f 100644
+--- a/nptl/register-atfork.c
++++ b/nptl/register-atfork.c
+@@ -21,6 +21,8 @@
+ #include
+ #include
+ #include
++#include
++#include
+
+ #define DYNARRAY_ELEMENT struct fork_handler
+ #define DYNARRAY_STRUCT fork_handler_list
+@@ -29,7 +31,7 @@
+ #include
+
+ static struct fork_handler_list fork_handlers;
+-static bool fork_handler_init = false;
++static uint64_t fork_handler_counter;
+
+ static int atfork_lock = LLL_LOCK_INITIALIZER;
+
+@@ -39,11 +41,8 @@ __register_atfork (void (*prepare) (void), void (*parent) (void),
+ {
+ lll_lock (atfork_lock, LLL_PRIVATE);
+
+- if (!fork_handler_init)
+- {
+- fork_handler_list_init (&fork_handlers);
+- fork_handler_init = true;
+- }
++ if (fork_handler_counter == 0)
++ fork_handler_list_init (&fork_handlers);
+
+ struct fork_handler *newp = fork_handler_list_emplace (&fork_handlers);
+ if (newp != NULL)
+@@ -52,6 +51,13 @@ __register_atfork (void (*prepare) (void), void (*parent) (void),
+ newp->parent_handler = parent;
+ newp->child_handler = child;
+ newp->dso_handle = dso_handle;
++
++ /* IDs assigned to handlers start at 1 and increment with handler
++ registration. Un-registering a handlers discards the corresponding
++ ID. It is not reused in future registrations. */
++ if (INT_ADD_OVERFLOW (fork_handler_counter, 1))
++ __libc_fatal ("fork handler counter overflow");
++ newp->id = ++fork_handler_counter;
+ }
+
+ /* Release the lock. */
+@@ -106,37 +112,111 @@ __unregister_atfork (void *dso_handle)
+ lll_unlock (atfork_lock, LLL_PRIVATE);
+ }
+
+-void
+-__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking)
++uint64_t
++__run_prefork_handlers (_Bool do_locking)
+ {
+- struct fork_handler *runp;
++ uint64_t lastrun;
+
+- if (who == atfork_run_prepare)
++ if (do_locking)
++ lll_lock (atfork_lock, LLL_PRIVATE);
++
++ /* We run prepare handlers from last to first. After fork, only
++ handlers up to the last handler found here (pre-fork) will be run.
++ Handlers registered during __run_prefork_handlers or
++ __run_postfork_handlers will be positioned after this last handler, and
++ since their prepare handlers won't be run now, their parent/child
++ handlers should also be ignored. */
++ lastrun = fork_handler_counter;
++
++ size_t sl = fork_handler_list_size (&fork_handlers);
++ for (size_t i = sl; i > 0;)
+ {
+- if (do_locking)
+- lll_lock (atfork_lock, LLL_PRIVATE);
+- size_t sl = fork_handler_list_size (&fork_handlers);
+- for (size_t i = sl; i > 0; i--)
+- {
+- runp = fork_handler_list_at (&fork_handlers, i - 1);
+- if (runp->prepare_handler != NULL)
+- runp->prepare_handler ();
+- }
++ struct fork_handler *runp
++ = fork_handler_list_at (&fork_handlers, i - 1);
++
++ uint64_t id = runp->id;
++
++ if (runp->prepare_handler != NULL)
++ {
++ if (do_locking)
++ lll_unlock (atfork_lock, LLL_PRIVATE);
++
++ runp->prepare_handler ();
++
++ if (do_locking)
++ lll_lock (atfork_lock, LLL_PRIVATE);
++ }
++
++ /* We unlocked, ran the handler, and locked again. In the
++ meanwhile, one or more deregistrations could have occurred leading
++ to the current (just run) handler being moved up the list or even
++ removed from the list itself. Since handler IDs are guaranteed to
++ to be in increasing order, the next handler has to have: */
++
++ /* A. An earlier position than the current one has. */
++ i--;
++
++ /* B. A lower ID than the current one does. The code below skips
++ any newly added handlers with higher IDs. */
++ while (i > 0
++ && fork_handler_list_at (&fork_handlers, i - 1)->id >= id)
++ i--;
+ }
+- else
++
++ return lastrun;
++}
++
++void
++__run_postfork_handlers (enum __run_fork_handler_type who, _Bool do_locking,
++ uint64_t lastrun)
++{
++ size_t sl = fork_handler_list_size (&fork_handlers);
++ for (size_t i = 0; i < sl;)
+ {
+- size_t sl = fork_handler_list_size (&fork_handlers);
+- for (size_t i = 0; i < sl; i++)
+- {
+- runp = fork_handler_list_at (&fork_handlers, i);
+- if (who == atfork_run_child && runp->child_handler)
+- runp->child_handler ();
+- else if (who == atfork_run_parent && runp->parent_handler)
+- runp->parent_handler ();
+- }
++ struct fork_handler *runp = fork_handler_list_at (&fork_handlers, i);
++ uint64_t id = runp->id;
++
++ /* prepare handlers were not run for handlers with ID > LASTRUN.
++ Thus, parent/child handlers will also not be run. */
++ if (id > lastrun)
++ break;
++
+ if (do_locking)
+- lll_unlock (atfork_lock, LLL_PRIVATE);
++ lll_unlock (atfork_lock, LLL_PRIVATE);
++
++ if (who == atfork_run_child && runp->child_handler)
++ runp->child_handler ();
++ else if (who == atfork_run_parent && runp->parent_handler)
++ runp->parent_handler ();
++
++ if (do_locking)
++ lll_lock (atfork_lock, LLL_PRIVATE);
++
++ /* We unlocked, ran the handler, and locked again. In the meanwhile,
++ one or more [de]registrations could have occurred. Due to this,
++ the list size must be updated. */
++ sl = fork_handler_list_size (&fork_handlers);
++
++ /* The just-run handler could also have moved up the list. */
++
++ if (sl > i && fork_handler_list_at (&fork_handlers, i)->id == id)
++ /* The position of the recently run handler hasn't changed. The
++ next handler to be run is an easy increment away. */
++ i++;
++ else
++ {
++ /* The next handler to be run is the first handler in the list
++ to have an ID higher than the current one. */
++ for (i = 0; i < sl; i++)
++ {
++ if (fork_handler_list_at (&fork_handlers, i)->id > id)
++ break;
++ }
++ }
+ }
++
++ if (do_locking)
++ lll_unlock (atfork_lock, LLL_PRIVATE);
+ }
+
+
+diff --git a/nptl/tst-atfork3.c b/nptl/tst-atfork3.c
+new file mode 100644
+index 0000000000000000..bb2250e432ab79ad
+--- /dev/null
++++ b/nptl/tst-atfork3.c
+@@ -0,0 +1,118 @@
++/* Check if pthread_atfork handler can call dlclose (BZ#24595).
++ 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
++ . */
++
++#include
++#include
++#include
++#include
++#include
++
++#include
++#include
++#include
++#include
++
++/* Check if pthread_atfork handlers do not deadlock when calling a function
++ that might alter the internal fork handle list, such as dlclose.
++
++ The test registers a callback set with pthread_atfork(), dlopen() a shared
++ library (nptl/tst-atfork3mod.c), calls an exported symbol from the library
++ (which in turn also registers atfork handlers), and calls fork to trigger
++ the callbacks. */
++
++static void *handler;
++static bool run_dlclose_prepare;
++static bool run_dlclose_parent;
++static bool run_dlclose_child;
++
++static void
++prepare (void)
++{
++ if (run_dlclose_prepare)
++ xdlclose (handler);
++}
++
++static void
++parent (void)
++{
++ if (run_dlclose_parent)
++ xdlclose (handler);
++}
++
++static void
++child (void)
++{
++ if (run_dlclose_child)
++ xdlclose (handler);
++}
++
++static void
++proc_func (void *closure)
++{
++}
++
++static void
++do_test_generic (bool dlclose_prepare, bool dlclose_parent, bool dlclose_child)
++{
++ run_dlclose_prepare = dlclose_prepare;
++ run_dlclose_parent = dlclose_parent;
++ run_dlclose_child = dlclose_child;
++
++ handler = xdlopen ("tst-atfork3mod.so", RTLD_NOW);
++
++ int (*atfork3mod_func)(void);
++ atfork3mod_func = xdlsym (handler, "atfork3mod_func");
++
++ atfork3mod_func ();
++
++ struct support_capture_subprocess proc
++ = support_capture_subprocess (proc_func, NULL);
++ support_capture_subprocess_check (&proc, "tst-atfork3", 0, sc_allow_none);
++
++ handler = atfork3mod_func = NULL;
++
++ support_capture_subprocess_free (&proc);
++}
++
++static void *
++thread_func (void *closure)
++{
++ return NULL;
++}
++
++static int
++do_test (void)
++{
++ {
++ /* Make the process acts as multithread. */
++ pthread_attr_t attr;
++ xpthread_attr_init (&attr);
++ xpthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
++ xpthread_create (&attr, thread_func, NULL);
++ }
++
++ TEST_COMPARE (pthread_atfork (prepare, parent, child), 0);
++
++ do_test_generic (true /* prepare */, false /* parent */, false /* child */);
++ do_test_generic (false /* prepare */, true /* parent */, false /* child */);
++ do_test_generic (false /* prepare */, false /* parent */, true /* child */);
++
++ return 0;
++}
++
++#include
+diff --git a/nptl/tst-atfork3mod.c b/nptl/tst-atfork3mod.c
+new file mode 100644
+index 0000000000000000..6d0658cb9efdecbc
+--- /dev/null
++++ b/nptl/tst-atfork3mod.c
+@@ -0,0 +1,44 @@
++/* 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
++ . */
++
++#include
++#include
++#include
++
++#include
++
++static void
++mod_prepare (void)
++{
++}
++
++static void
++mod_parent (void)
++{
++}
++
++static void
++mod_child (void)
++{
++}
++
++int atfork3mod_func (void)
++{
++ TEST_COMPARE (pthread_atfork (mod_prepare, mod_parent, mod_child), 0);
++
++ return 0;
++}
+diff --git a/nptl/tst-atfork4.c b/nptl/tst-atfork4.c
+new file mode 100644
+index 0000000000000000..52dc87e73b846ab9
+--- /dev/null
++++ b/nptl/tst-atfork4.c
+@@ -0,0 +1,128 @@
++/* pthread_atfork supports handlers that call pthread_atfork or dlclose.
++ 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
++ . */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++static void *
++thread_func (void *x)
++{
++ return NULL;
++}
++
++static unsigned int second_atfork_handler_runcount = 0;
++
++static void
++second_atfork_handler (void)
++{
++ second_atfork_handler_runcount++;
++}
++
++static void *h = NULL;
++
++static unsigned int atfork_handler_runcount = 0;
++
++static void
++prepare (void)
++{
++ /* These atfork handlers are registered while atfork handlers are being
++ executed and thus will not be executed during the corresponding
++ fork. */
++ TEST_VERIFY_EXIT (pthread_atfork (second_atfork_handler,
++ second_atfork_handler,
++ second_atfork_handler) == 0);
++
++ /* This will de-register the atfork handlers registered by the dlopen'd
++ library and so they will not be executed. */
++ if (h != NULL)
++ {
++ xdlclose (h);
++ h = NULL;
++ }
++
++ atfork_handler_runcount++;
++}
++
++static void
++after (void)
++{
++ atfork_handler_runcount++;
++}
++
++static int
++do_test (void)
++{
++ /* Make sure __libc_single_threaded is 0. */
++ pthread_attr_t attr;
++ xpthread_attr_init (&attr);
++ xpthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
++ xpthread_create (&attr, thread_func, NULL);
++
++ void (*reg_atfork_handlers) (void);
++
++ h = xdlopen ("tst-atfork4mod.so", RTLD_LAZY);
++
++ reg_atfork_handlers = xdlsym (h, "reg_atfork_handlers");
++
++ reg_atfork_handlers ();
++
++ /* We register our atfork handlers *after* loading the module so that our
++ prepare handler is called first at fork, where we then dlclose the
++ module before its prepare handler has a chance to be called. */
++ TEST_VERIFY_EXIT (pthread_atfork (prepare, after, after) == 0);
++
++ pid_t pid = xfork ();
++
++ /* Both the parent and the child processes should observe this. */
++ TEST_VERIFY_EXIT (atfork_handler_runcount == 2);
++ TEST_VERIFY_EXIT (second_atfork_handler_runcount == 0);
++
++ if (pid > 0)
++ {
++ int childstat;
++
++ xwaitpid (-1, &childstat, 0);
++ TEST_VERIFY_EXIT (WIFEXITED (childstat)
++ && WEXITSTATUS (childstat) == 0);
++
++ /* This time, the second set of atfork handlers should also be called
++ since the handlers are already in place before fork is called. */
++
++ pid = xfork ();
++
++ TEST_VERIFY_EXIT (atfork_handler_runcount == 4);
++ TEST_VERIFY_EXIT (second_atfork_handler_runcount == 2);
++
++ if (pid > 0)
++ {
++ xwaitpid (-1, &childstat, 0);
++ TEST_VERIFY_EXIT (WIFEXITED (childstat)
++ && WEXITSTATUS (childstat) == 0);
++ }
++ }
++
++ return 0;
++}
++
++#include
+diff --git a/nptl/tst-atfork4mod.c b/nptl/tst-atfork4mod.c
+new file mode 100644
+index 0000000000000000..e111efeb185916e0
+--- /dev/null
++++ b/nptl/tst-atfork4mod.c
+@@ -0,0 +1,48 @@
++/* pthread_atfork supports handlers that call pthread_atfork or dlclose.
++ 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
++ . */
++
++#include
++#include
++
++/* This dynamically loaded library simply registers its atfork handlers when
++ asked to. The atfork handlers should never be executed because the
++ library is unloaded before fork is called by the test program. */
++
++static void
++prepare (void)
++{
++ abort ();
++}
++
++static void
++parent (void)
++{
++ abort ();
++}
++
++static void
++child (void)
++{
++ abort ();
++}
++
++void
++reg_atfork_handlers (void)
++{
++ pthread_atfork (prepare, parent, child);
++}
+diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
+index b4d20fa652f4ba3b..1324b813136764fc 100644
+--- a/sysdeps/nptl/fork.c
++++ b/sysdeps/nptl/fork.c
+@@ -54,8 +54,9 @@ __libc_fork (void)
+ signal handlers. POSIX requires that fork is async-signal-safe,
+ but our current fork implementation is not. */
+ bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads);
++ uint64_t lastrun;
+
+- __run_fork_handlers (atfork_run_prepare, multiple_threads);
++ lastrun = __run_prefork_handlers (multiple_threads);
+
+ /* If we are not running multiple threads, we do not have to
+ preserve lock state. If fork runs from a signal handler, only
+@@ -129,7 +130,7 @@ __libc_fork (void)
+ __rtld_lock_initialize (GL(dl_load_tls_lock));
+
+ /* Run the handlers registered for the child. */
+- __run_fork_handlers (atfork_run_child, multiple_threads);
++ __run_postfork_handlers (atfork_run_child, multiple_threads, lastrun);
+ }
+ else
+ {
+@@ -144,7 +145,7 @@ __libc_fork (void)
+ }
+
+ /* Run the handlers registered for the parent. */
+- __run_fork_handlers (atfork_run_parent, multiple_threads);
++ __run_postfork_handlers (atfork_run_parent, multiple_threads, lastrun);
+ }
+
+ return pid;
+diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h
+index bef2b7a8a6af8635..222c4f618970a455 100644
+--- a/sysdeps/nptl/fork.h
++++ b/sysdeps/nptl/fork.h
+@@ -31,6 +31,7 @@ struct fork_handler
+ void (*parent_handler) (void);
+ void (*child_handler) (void);
+ void *dso_handle;
++ uint64_t id;
+ };
+
+ /* Function to call to unregister fork handlers. */
+@@ -44,19 +45,18 @@ enum __run_fork_handler_type
+ atfork_run_parent
+ };
+
+-/* Run the atfork handlers and lock/unlock the internal lock depending
+- of the WHO argument:
++/* Run the atfork prepare handlers in the reverse order of registration and
++ return the ID of the last registered handler. If DO_LOCKING is true, the
++ internal lock is held locked upon return. */
++extern uint64_t __run_prefork_handlers (_Bool do_locking) attribute_hidden;
+
+- - atfork_run_prepare: run all the PREPARE_HANDLER in reverse order of
+- insertion and locks the internal lock.
+- - atfork_run_child: run all the CHILD_HANDLER and unlocks the internal
+- lock.
+- - atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal
+- lock.
+-
+- Perform locking only if DO_LOCKING. */
+-extern void __run_fork_handlers (enum __run_fork_handler_type who,
+- _Bool do_locking) attribute_hidden;
++/* Given a handler type (parent or child), run all the atfork handlers in
++ the order of registration up to and including the handler with id equal
++ to LASTRUN. If DO_LOCKING is true, the internal lock is unlocked prior
++ to return. */
++extern void __run_postfork_handlers (enum __run_fork_handler_type who,
++ _Bool do_locking,
++ uint64_t lastrun) attribute_hidden;
+
+ /* C library side function to register new fork handlers. */
+ extern int __register_atfork (void (*__prepare) (void),
diff --git a/glibc-rh2084564.patch b/glibc-rh1961109.patch
similarity index 100%
rename from glibc-rh2084564.patch
rename to glibc-rh1961109.patch
diff --git a/glibc-rh1982608.patch b/glibc-rh1982608.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6f67ed6ddc341ec28384941a2be824cb7b97d0d9
--- /dev/null
+++ b/glibc-rh1982608.patch
@@ -0,0 +1,2216 @@
+This is a rebase of posix/glob.c from upstream (gnulib->glibc->rhel).
+
+Relevent upstream commits:
+
+7c477b57a31487eda516db02b9e04f22d1a6e6af posix/glob.c: update from gnulib
+ (This is the master commit to which we're syncing)
+
+gnulib commit 98f034a0c2ba8917c96f363de1a8d66244e411da
+ (This is the gnulib commit to which glibc upstream sync'd)
+
+Additional glibc upstream commits of note:
+84f7ce84474c1648ce96884f1c91ca7b97ca3fc2 posix: Add glob64 with 64-bit time_t support
+ (just posix/glob.c and sysdeps/gnu/glob64-lstat-compat.c)
+9a7ab0769b295cbf5232140401742a8f34bda3de hurd: Fix glob lstat compatibility
+4883360415f1ed772ba44decc501d59deb17bdf0 posix: Sync glob code with gnulib
+04986243d1af37ac0177ed2f9db0a066ebd2b212 Remove internal usage of extensible stat functions
+ddc650e9b3dc916eab417ce9f79e67337b05035c Fix use-after-free in glob when expanding ~user (bug 25414)
+
+
+diff -rup a/posix/glob-lstat-compat.c b/posix/glob-lstat-compat.c
+--- a/posix/glob-lstat-compat.c 2018-08-01 01:10:47.000000000 -0400
++++ b/posix/glob-lstat-compat.c 2022-05-02 22:49:06.504676711 -0400
+@@ -28,7 +28,8 @@
+ # define GLOB_ATTRIBUTE attribute_compat_text_section
+
+ /* Avoid calling gl_lstat with GLOB_ALTDIRFUNC. */
+-# define GLOB_NO_LSTAT
++# define GLOB_LSTAT gl_stat
++# define GLOB_LSTAT64 __stat64
+
+ # include
+
+diff -rup a/posix/glob.c b/posix/glob.c
+--- a/posix/glob.c 2022-05-03 14:37:52.959042051 -0400
++++ b/posix/glob.c 2022-05-02 22:49:18.655134696 -0400
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
++/* Copyright (C) 1991-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
+@@ -13,11 +13,22 @@
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+- . */
++ . */
++
++#ifndef _LIBC
++
++/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
++ optimizes away the pattern == NULL test below. */
++# define _GL_ARG_NONNULL(params)
++
++# include
++
++#endif
+
+ #include
+
+ #include
++#include
+ #include
+ #include
+ #include
+@@ -26,7 +37,7 @@
+ #include
+ #include
+
+-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++#if defined _WIN32 && ! defined __CYGWIN__
+ # define WINDOWS32
+ #endif
+
+@@ -46,30 +57,38 @@
+ # define sysconf(id) __sysconf (id)
+ # define closedir(dir) __closedir (dir)
+ # define opendir(name) __opendir (name)
++# undef dirfd
++# define dirfd(str) __dirfd (str)
+ # define readdir(str) __readdir64 (str)
+ # define getpwnam_r(name, bufp, buf, len, res) \
+ __getpwnam_r (name, bufp, buf, len, res)
+-# ifndef __lstat64
+-# define __lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf)
++# define FLEXIBLE_ARRAY_MEMBER
++# ifndef struct_stat
++# define struct_stat struct stat
+ # endif
+-# ifndef __stat64
+-# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
++# ifndef struct_stat64
++# define struct_stat64 struct stat64
++# endif
++# ifndef GLOB_LSTAT
++# define GLOB_LSTAT gl_lstat
++# endif
++# ifndef GLOB_FSTATAT64
++# define GLOB_FSTATAT64 __fstatat64
+ # endif
+-# define struct_stat64 struct stat64
+-# define FLEXIBLE_ARRAY_MEMBER
+ # include
+ #else /* !_LIBC */
+ # define __glob glob
+ # define __getlogin_r(buf, len) getlogin_r (buf, len)
+-# define __lstat64(fname, buf) lstat (fname, buf)
+-# define __stat64(fname, buf) stat (fname, buf)
+ # define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
+-# define struct_stat64 struct stat
+ # ifndef __MVS__
+ # define __alloca alloca
+ # endif
+ # define __readdir readdir
+ # define COMPILE_GLOB64
++# define struct_stat struct stat
++# define struct_stat64 struct stat
++# define GLOB_LSTAT gl_lstat
++# define GLOB_FSTATAT64 fstatat
+ #endif /* _LIBC */
+
+ #include
+@@ -80,7 +99,9 @@
+
+ static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
+
+-typedef uint_fast8_t dirent_type;
++/* The type of ((struct dirent *) 0)->d_type is 'unsigned char' on most
++ platforms, but 'unsigned int' in the mingw from mingw.org. */
++typedef uint_fast32_t dirent_type;
+
+ #if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE
+ /* Any distinct values will do here.
+@@ -119,9 +140,9 @@ readdir_result_type (struct readdir_resu
+ /* Construct an initializer for a struct readdir_result object from a
+ struct dirent *. No copy of the name is made. */
+ #define READDIR_RESULT_INITIALIZER(source) \
+- { \
+- source->d_name, \
+- D_TYPE_TO_RESULT (source) \
++ { \
++ source->d_name, \
++ D_TYPE_TO_RESULT (source) \
+ }
+
+ /* Call gl_readdir on STREAM. This macro can be overridden to reduce
+@@ -186,22 +207,15 @@ glob_lstat (glob_t *pglob, int flags, co
+ {
+ /* Use on glob-lstat-compat.c to provide a compat symbol which does not
+ use lstat / gl_lstat. */
+-#ifdef GLOB_NO_LSTAT
+-# define GL_LSTAT gl_stat
+-# define LSTAT64 __stat64
+-#else
+-# define GL_LSTAT gl_lstat
+-# define LSTAT64 __lstat64
+-#endif
+-
+ union
+ {
+- struct stat st;
++ struct_stat st;
+ struct_stat64 st64;
+ } ust;
+ return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
+- ? pglob->GL_LSTAT (fullname, &ust.st)
+- : LSTAT64 (fullname, &ust.st64));
++ ? pglob->GLOB_LSTAT (fullname, &ust.st)
++ : GLOB_FSTATAT64 (AT_FDCWD, fullname, &ust.st64,
++ AT_SYMLINK_NOFOLLOW));
+ }
+
+ /* Set *R = A + B. Return true if the answer is mathematically
+@@ -211,7 +225,7 @@ glob_lstat (glob_t *pglob, int flags, co
+ static bool
+ size_add_wrapv (size_t a, size_t b, size_t *r)
+ {
+-#if 5 <= __GNUC__ && !defined __ICC
++#if 7 <= __GNUC__ && !defined __ICC
+ return __builtin_add_overflow (a, b, r);
+ #else
+ *r = a + b;
+@@ -228,8 +242,8 @@ glob_use_alloca (size_t alloca_used, siz
+ }
+
+ static int glob_in_dir (const char *pattern, const char *directory,
+- int flags, int (*errfunc) (const char *, int),
+- glob_t *pglob, size_t alloca_used);
++ int flags, int (*errfunc) (const char *, int),
++ glob_t *pglob, size_t alloca_used);
+ static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
+ static int collated_compare (const void *, const void *) __THROWNL;
+
+@@ -239,11 +253,12 @@ static int collated_compare (const void
+ static bool
+ is_dir (char const *filename, int flags, glob_t const *pglob)
+ {
+- struct stat st;
++ struct_stat st;
+ struct_stat64 st64;
+ return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
+ ? pglob->gl_stat (filename, &st) == 0 && S_ISDIR (st.st_mode)
+- : __stat64 (filename, &st64) == 0 && S_ISDIR (st64.st_mode));
++ : (GLOB_FSTATAT64 (AT_FDCWD, filename, &st64, 0) == 0
++ && S_ISDIR (st64.st_mode)));
+ }
+
+ /* Find the end of the sub-pattern in a brace expression. */
+@@ -254,17 +269,17 @@ next_brace_sub (const char *cp, int flag
+ while (*cp != '\0')
+ if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
+ {
+- if (*++cp == '\0')
+- break;
+- ++cp;
++ if (*++cp == '\0')
++ break;
++ ++cp;
+ }
+ else
+ {
+- if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
+- break;
++ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
++ break;
+
+- if (*cp++ == '{')
+- depth++;
++ if (*cp++ == '{')
++ depth++;
+ }
+
+ return *cp != '\0' ? cp : NULL;
+@@ -285,7 +300,7 @@ next_brace_sub (const char *cp, int flag
+ int
+ GLOB_ATTRIBUTE
+ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
+- glob_t *pglob)
++ glob_t *pglob)
+ {
+ const char *filename;
+ char *dirname = NULL;
+@@ -319,22 +334,22 @@ __glob (const char *pattern, int flags,
+ {
+ pglob->gl_pathc = 0;
+ if (!(flags & GLOB_DOOFFS))
+- pglob->gl_pathv = NULL;
++ pglob->gl_pathv = NULL;
+ else
+- {
+- size_t i;
++ {
++ size_t i;
+
+- if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *))
+- return GLOB_NOSPACE;
++ if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *))
++ return GLOB_NOSPACE;
+
+- pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1)
+- * sizeof (char *));
+- if (pglob->gl_pathv == NULL)
+- return GLOB_NOSPACE;
+-
+- for (i = 0; i <= pglob->gl_offs; ++i)
+- pglob->gl_pathv[i] = NULL;
+- }
++ pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1)
++ * sizeof (char *));
++ if (pglob->gl_pathv == NULL)
++ return GLOB_NOSPACE;
++
++ for (i = 0; i <= pglob->gl_offs; ++i)
++ pglob->gl_pathv[i] = NULL;
++ }
+ }
+
+ if (flags & GLOB_BRACE)
+@@ -342,129 +357,129 @@ __glob (const char *pattern, int flags,
+ const char *begin;
+
+ if (flags & GLOB_NOESCAPE)
+- begin = strchr (pattern, '{');
++ begin = strchr (pattern, '{');
+ else
+- {
+- begin = pattern;
+- while (1)
+- {
+- if (*begin == '\0')
+- {
+- begin = NULL;
+- break;
+- }
+-
+- if (*begin == '\\' && begin[1] != '\0')
+- ++begin;
+- else if (*begin == '{')
+- break;
+-
+- ++begin;
+- }
+- }
++ {
++ begin = pattern;
++ while (1)
++ {
++ if (*begin == '\0')
++ {
++ begin = NULL;
++ break;
++ }
++
++ if (*begin == '\\' && begin[1] != '\0')
++ ++begin;
++ else if (*begin == '{')
++ break;
++
++ ++begin;
++ }
++ }
+
+ if (begin != NULL)
+- {
+- /* Allocate working buffer large enough for our work. Note that
+- we have at least an opening and closing brace. */
+- size_t firstc;
+- char *alt_start;
+- const char *p;
+- const char *next;
+- const char *rest;
+- size_t rest_len;
+- char *onealt;
+- size_t pattern_len = strlen (pattern) - 1;
+- int alloca_onealt = glob_use_alloca (alloca_used, pattern_len);
+- if (alloca_onealt)
+- onealt = alloca_account (pattern_len, alloca_used);
+- else
+- {
+- onealt = malloc (pattern_len);
+- if (onealt == NULL)
+- return GLOB_NOSPACE;
+- }
+-
+- /* We know the prefix for all sub-patterns. */
+- alt_start = mempcpy (onealt, pattern, begin - pattern);
+-
+- /* Find the first sub-pattern and at the same time find the
+- rest after the closing brace. */
+- next = next_brace_sub (begin + 1, flags);
+- if (next == NULL)
+- {
+- /* It is an invalid expression. */
+- illegal_brace:
+- if (__glibc_unlikely (!alloca_onealt))
+- free (onealt);
+- flags &= ~GLOB_BRACE;
+- goto no_brace;
+- }
+-
+- /* Now find the end of the whole brace expression. */
+- rest = next;
+- while (*rest != '}')
+- {
+- rest = next_brace_sub (rest + 1, flags);
+- if (rest == NULL)
+- /* It is an illegal expression. */
+- goto illegal_brace;
+- }
+- /* Please note that we now can be sure the brace expression
+- is well-formed. */
+- rest_len = strlen (++rest) + 1;
+-
+- /* We have a brace expression. BEGIN points to the opening {,
+- NEXT points past the terminator of the first element, and END
+- points past the final }. We will accumulate result names from
+- recursive runs for each brace alternative in the buffer using
+- GLOB_APPEND. */
+- firstc = pglob->gl_pathc;
+-
+- p = begin + 1;
+- while (1)
+- {
+- int result;
+-
+- /* Construct the new glob expression. */
+- mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
+-
+- result = __glob (onealt,
+- ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+- | GLOB_APPEND),
+- errfunc, pglob);
+-
+- /* If we got an error, return it. */
+- if (result && result != GLOB_NOMATCH)
+- {
+- if (__glibc_unlikely (!alloca_onealt))
+- free (onealt);
+- if (!(flags & GLOB_APPEND))
+- {
+- globfree (pglob);
+- pglob->gl_pathc = 0;
+- }
+- return result;
+- }
+-
+- if (*next == '}')
+- /* We saw the last entry. */
+- break;
+-
+- p = next + 1;
+- next = next_brace_sub (p, flags);
+- assert (next != NULL);
+- }
+-
+- if (__glibc_unlikely (!alloca_onealt))
+- free (onealt);
+-
+- if (pglob->gl_pathc != firstc)
+- /* We found some entries. */
+- return 0;
+- else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+- return GLOB_NOMATCH;
+- }
++ {
++ /* Allocate working buffer large enough for our work. Note that
++ we have at least an opening and closing brace. */
++ size_t firstc;
++ char *alt_start;
++ const char *p;
++ const char *next;
++ const char *rest;
++ size_t rest_len;
++ char *onealt;
++ size_t pattern_len = strlen (pattern) - 1;
++ int alloca_onealt = glob_use_alloca (alloca_used, pattern_len);
++ if (alloca_onealt)
++ onealt = alloca_account (pattern_len, alloca_used);
++ else
++ {
++ onealt = malloc (pattern_len);
++ if (onealt == NULL)
++ return GLOB_NOSPACE;
++ }
++
++ /* We know the prefix for all sub-patterns. */
++ alt_start = mempcpy (onealt, pattern, begin - pattern);
++
++ /* Find the first sub-pattern and at the same time find the
++ rest after the closing brace. */
++ next = next_brace_sub (begin + 1, flags);
++ if (next == NULL)
++ {
++ /* It is an invalid expression. */
++ illegal_brace:
++ if (__glibc_unlikely (!alloca_onealt))
++ free (onealt);
++ flags &= ~GLOB_BRACE;
++ goto no_brace;
++ }
++
++ /* Now find the end of the whole brace expression. */
++ rest = next;
++ while (*rest != '}')
++ {
++ rest = next_brace_sub (rest + 1, flags);
++ if (rest == NULL)
++ /* It is an illegal expression. */
++ goto illegal_brace;
++ }
++ /* Please note that we now can be sure the brace expression
++ is well-formed. */
++ rest_len = strlen (++rest) + 1;
++
++ /* We have a brace expression. BEGIN points to the opening {,
++ NEXT points past the terminator of the first element, and END
++ points past the final }. We will accumulate result names from
++ recursive runs for each brace alternative in the buffer using
++ GLOB_APPEND. */
++ firstc = pglob->gl_pathc;
++
++ p = begin + 1;
++ while (1)
++ {
++ int result;
++
++ /* Construct the new glob expression. */
++ mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
++
++ result = __glob (onealt,
++ ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
++ | GLOB_APPEND),
++ errfunc, pglob);
++
++ /* If we got an error, return it. */
++ if (result && result != GLOB_NOMATCH)
++ {
++ if (__glibc_unlikely (!alloca_onealt))
++ free (onealt);
++ if (!(flags & GLOB_APPEND))
++ {
++ globfree (pglob);
++ pglob->gl_pathc = 0;
++ }
++ return result;
++ }
++
++ if (*next == '}')
++ /* We saw the last entry. */
++ break;
++
++ p = next + 1;
++ next = next_brace_sub (p, flags);
++ assert (next != NULL);
++ }
++
++ if (__glibc_unlikely (!alloca_onealt))
++ free (onealt);
++
++ if (pglob->gl_pathc != firstc)
++ /* We found some entries. */
++ return 0;
++ else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
++ return GLOB_NOMATCH;
++ }
+ }
+
+ no_brace:
+@@ -486,33 +501,33 @@ __glob (const char *pattern, int flags,
+ if (filename == NULL)
+ {
+ /* This can mean two things: a simple name or "~name". The latter
+- case is nothing but a notation for a directory. */
++ case is nothing but a notation for a directory. */
+ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
+- {
+- dirname = (char *) pattern;
+- dirlen = strlen (pattern);
+-
+- /* Set FILENAME to NULL as a special flag. This is ugly but
+- other solutions would require much more code. We test for
+- this special case below. */
+- filename = NULL;
+- }
++ {
++ dirname = (char *) pattern;
++ dirlen = strlen (pattern);
++
++ /* Set FILENAME to NULL as a special flag. This is ugly but
++ other solutions would require much more code. We test for
++ this special case below. */
++ filename = NULL;
++ }
+ else
+- {
+- if (__glibc_unlikely (pattern[0] == '\0'))
+- {
+- dirs.gl_pathv = NULL;
+- goto no_matches;
+- }
+-
+- filename = pattern;
+- dirname = (char *) ".";
+- dirlen = 0;
+- }
++ {
++ if (__glibc_unlikely (pattern[0] == '\0'))
++ {
++ dirs.gl_pathv = NULL;
++ goto no_matches;
++ }
++
++ filename = pattern;
++ dirname = (char *) ".";
++ dirlen = 0;
++ }
+ }
+ else if (filename == pattern
+- || (filename == pattern + 1 && pattern[0] == '\\'
+- && (flags & GLOB_NOESCAPE) == 0))
++ || (filename == pattern + 1 && pattern[0] == '\\'
++ && (flags & GLOB_NOESCAPE) == 0))
+ {
+ /* "/pattern" or "\\/pattern". */
+ dirname = (char *) "/";
+@@ -525,32 +540,32 @@ __glob (const char *pattern, int flags,
+ dirlen = filename - pattern;
+ #if defined __MSDOS__ || defined WINDOWS32
+ if (*filename == ':'
+- || (filename > pattern + 1 && filename[-1] == ':'))
+- {
+- char *drive_spec;
+-
+- ++dirlen;
+- drive_spec = __alloca (dirlen + 1);
+- *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
+- /* For now, disallow wildcards in the drive spec, to
+- prevent infinite recursion in glob. */
+- if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
+- return GLOB_NOMATCH;
+- /* If this is "d:pattern", we need to copy ':' to DIRNAME
+- as well. If it's "d:/pattern", don't remove the slash
+- from "d:/", since "d:" and "d:/" are not the same.*/
+- }
++ || (filename > pattern + 1 && filename[-1] == ':'))
++ {
++ char *drive_spec;
++
++ ++dirlen;
++ drive_spec = __alloca (dirlen + 1);
++ *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
++ /* For now, disallow wildcards in the drive spec, to
++ prevent infinite recursion in glob. */
++ if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
++ return GLOB_NOMATCH;
++ /* If this is "d:pattern", we need to copy ':' to DIRNAME
++ as well. If it's "d:/pattern", don't remove the slash
++ from "d:/", since "d:" and "d:/" are not the same.*/
++ }
+ #endif
+
+ if (glob_use_alloca (alloca_used, dirlen + 1))
+- newp = alloca_account (dirlen + 1, alloca_used);
++ newp = alloca_account (dirlen + 1, alloca_used);
+ else
+- {
+- newp = malloc (dirlen + 1);
+- if (newp == NULL)
+- return GLOB_NOSPACE;
+- malloc_dirname = 1;
+- }
++ {
++ newp = malloc (dirlen + 1);
++ if (newp == NULL)
++ return GLOB_NOSPACE;
++ malloc_dirname = 1;
++ }
+ *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
+ dirname = newp;
+ ++filename;
+@@ -566,363 +581,383 @@ __glob (const char *pattern, int flags,
+
+ if (filename[0] == '\0' && dirlen > 1 && !drive_root)
+ /* "pattern/". Expand "pattern", appending slashes. */
+- {
+- int orig_flags = flags;
+- if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
+- {
+- /* "pattern\\/". Remove the final backslash if it hasn't
+- been quoted. */
+- char *p = (char *) &dirname[dirlen - 1];
+-
+- while (p > dirname && p[-1] == '\\') --p;
+- if ((&dirname[dirlen] - p) & 1)
+- {
+- *(char *) &dirname[--dirlen] = '\0';
+- flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
+- }
+- }
+- int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+- if (val == 0)
+- pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
+- | (flags & GLOB_MARK));
+- else if (val == GLOB_NOMATCH && flags != orig_flags)
+- {
+- /* Make sure globfree (&dirs); is a nop. */
+- dirs.gl_pathv = NULL;
+- flags = orig_flags;
+- oldcount = pglob->gl_pathc + pglob->gl_offs;
+- goto no_matches;
+- }
+- retval = val;
+- goto out;
+- }
++ {
++ int orig_flags = flags;
++ if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
++ {
++ /* "pattern\\/". Remove the final backslash if it hasn't
++ been quoted. */
++ char *p = (char *) &dirname[dirlen - 1];
++
++ while (p > dirname && p[-1] == '\\') --p;
++ if ((&dirname[dirlen] - p) & 1)
++ {
++ *(char *) &dirname[--dirlen] = '\0';
++ flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
++ }
++ }
++ int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob);
++ if (val == 0)
++ pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
++ | (flags & GLOB_MARK));
++ else if (val == GLOB_NOMATCH && flags != orig_flags)
++ {
++ /* Make sure globfree (&dirs); is a nop. */
++ dirs.gl_pathv = NULL;
++ flags = orig_flags;
++ oldcount = pglob->gl_pathc + pglob->gl_offs;
++ goto no_matches;
++ }
++ retval = val;
++ goto out;
++ }
+ }
+
+ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
+ {
+ if (dirname[1] == '\0' || dirname[1] == '/'
+- || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\'
+- && (dirname[2] == '\0' || dirname[2] == '/')))
+- {
+- /* Look up home directory. */
+- char *home_dir = getenv ("HOME");
+- int malloc_home_dir = 0;
+- if (home_dir == NULL || home_dir[0] == '\0')
+- {
++ || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\'
++ && (dirname[2] == '\0' || dirname[2] == '/')))
++ {
++ /* Look up home directory. */
++ char *home_dir = getenv ("HOME");
++ int malloc_home_dir = 0;
++ if (home_dir == NULL || home_dir[0] == '\0')
++ {
+ #ifdef WINDOWS32
+- /* Windows NT defines HOMEDRIVE and HOMEPATH. But give
+- preference to HOME, because the user can change HOME. */
+- const char *home_drive = getenv ("HOMEDRIVE");
+- const char *home_path = getenv ("HOMEPATH");
+-
+- if (home_drive != NULL && home_path != NULL)
+- {
+- size_t home_drive_len = strlen (home_drive);
+- size_t home_path_len = strlen (home_path);
+- char *mem = alloca (home_drive_len + home_path_len + 1);
+-
+- memcpy (mem, home_drive, home_drive_len);
+- memcpy (mem + home_drive_len, home_path, home_path_len + 1);
+- home_dir = mem;
+- }
+- else
+- home_dir = "c:/users/default"; /* poor default */
++ /* Windows NT defines HOMEDRIVE and HOMEPATH. But give
++ preference to HOME, because the user can change HOME. */
++ const char *home_drive = getenv ("HOMEDRIVE");
++ const char *home_path = getenv ("HOMEPATH");
++
++ if (home_drive != NULL && home_path != NULL)
++ {
++ size_t home_drive_len = strlen (home_drive);
++ size_t home_path_len = strlen (home_path);
++ char *mem = alloca (home_drive_len + home_path_len + 1);
++
++ memcpy (mem, home_drive, home_drive_len);
++ memcpy (mem + home_drive_len, home_path, home_path_len + 1);
++ home_dir = mem;
++ }
++ else
++ home_dir = "c:/users/default"; /* poor default */
+ #else
+- int err;
+- struct passwd *p;
+- struct passwd pwbuf;
+- struct scratch_buffer s;
+- scratch_buffer_init (&s);
+- while (true)
+- {
+- p = NULL;
+- err = __getlogin_r (s.data, s.length);
+- if (err == 0)
+- {
++ int err;
++ struct passwd *p;
++ struct passwd pwbuf;
++ struct scratch_buffer s;
++ scratch_buffer_init (&s);
++ while (true)
++ {
++ p = NULL;
++ err = __getlogin_r (s.data, s.length);
++ if (err == 0)
++ {
+ # if defined HAVE_GETPWNAM_R || defined _LIBC
+- size_t ssize = strlen (s.data) + 1;
+- char *sdata = s.data;
+- err = getpwnam_r (sdata, &pwbuf, sdata + ssize,
+- s.length - ssize, &p);
++ size_t ssize = strlen (s.data) + 1;
++ char *sdata = s.data;
++ err = getpwnam_r (sdata, &pwbuf, sdata + ssize,
++ s.length - ssize, &p);
+ # else
+- p = getpwnam (s.data);
+- if (p == NULL)
+- err = errno;
++ p = getpwnam (s.data);
++ if (p == NULL)
++ err = errno;
+ # endif
+- }
+- if (err != ERANGE)
+- break;
+- if (!scratch_buffer_grow (&s))
+- {
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+- }
+- if (err == 0)
+- {
+- home_dir = strdup (p->pw_dir);
+- malloc_home_dir = 1;
+- }
+- scratch_buffer_free (&s);
+- if (err == 0 && home_dir == NULL)
+- {
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
++ }
++ if (err != ERANGE)
++ break;
++ if (!scratch_buffer_grow (&s))
++ {
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
++ }
++ if (err == 0)
++ {
++ home_dir = strdup (p->pw_dir);
++ malloc_home_dir = 1;
++ }
++ scratch_buffer_free (&s);
++ if (err == 0 && home_dir == NULL)
++ {
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
+ #endif /* WINDOWS32 */
+- }
+- if (home_dir == NULL || home_dir[0] == '\0')
+- {
+- if (__glibc_unlikely (malloc_home_dir))
+- free (home_dir);
+- if (flags & GLOB_TILDE_CHECK)
+- {
+- retval = GLOB_NOMATCH;
+- goto out;
+- }
+- else
+- {
+- home_dir = (char *) "~"; /* No luck. */
+- malloc_home_dir = 0;
+- }
+- }
+- /* Now construct the full directory. */
+- if (dirname[1] == '\0')
+- {
+- if (__glibc_unlikely (malloc_dirname))
+- free (dirname);
+-
+- dirname = home_dir;
+- dirlen = strlen (dirname);
+- malloc_dirname = malloc_home_dir;
+- }
+- else
+- {
+- char *newp;
+- size_t home_len = strlen (home_dir);
+- int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen);
+- if (use_alloca)
+- newp = alloca_account (home_len + dirlen, alloca_used);
+- else
+- {
+- newp = malloc (home_len + dirlen);
+- if (newp == NULL)
+- {
+- if (__glibc_unlikely (malloc_home_dir))
+- free (home_dir);
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+- }
+-
+- mempcpy (mempcpy (newp, home_dir, home_len),
+- &dirname[1], dirlen);
+-
+- if (__glibc_unlikely (malloc_dirname))
+- free (dirname);
+-
+- dirname = newp;
+- dirlen += home_len - 1;
+- malloc_dirname = !use_alloca;
+-
+- if (__glibc_unlikely (malloc_home_dir))
+- free (home_dir);
+- }
+- dirname_modified = 1;
+- }
++ }
++ if (home_dir == NULL || home_dir[0] == '\0')
++ {
++ if (__glibc_unlikely (malloc_home_dir))
++ free (home_dir);
++ if (flags & GLOB_TILDE_CHECK)
++ {
++ retval = GLOB_NOMATCH;
++ goto out;
++ }
++ else
++ {
++ home_dir = (char *) "~"; /* No luck. */
++ malloc_home_dir = 0;
++ }
++ }
++ /* Now construct the full directory. */
++ if (dirname[1] == '\0')
++ {
++ if (__glibc_unlikely (malloc_dirname))
++ free (dirname);
++
++ dirname = home_dir;
++ dirlen = strlen (dirname);
++ malloc_dirname = malloc_home_dir;
++ }
++ else
++ {
++ char *newp;
++ size_t home_len = strlen (home_dir);
++ int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen);
++ if (use_alloca)
++ newp = alloca_account (home_len + dirlen, alloca_used);
++ else
++ {
++ newp = malloc (home_len + dirlen);
++ if (newp == NULL)
++ {
++ if (__glibc_unlikely (malloc_home_dir))
++ free (home_dir);
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
++ }
++
++ mempcpy (mempcpy (newp, home_dir, home_len),
++ &dirname[1], dirlen);
++
++ if (__glibc_unlikely (malloc_dirname))
++ free (dirname);
++
++ dirname = newp;
++ dirlen += home_len - 1;
++ malloc_dirname = !use_alloca;
++
++ if (__glibc_unlikely (malloc_home_dir))
++ free (home_dir);
++ }
++ dirname_modified = 1;
++ }
+ else
+- {
++ {
+ #ifndef WINDOWS32
+- char *end_name = strchr (dirname, '/');
+- char *user_name;
+- int malloc_user_name = 0;
+- char *unescape = NULL;
+-
+- if (!(flags & GLOB_NOESCAPE))
+- {
+- if (end_name == NULL)
+- {
+- unescape = strchr (dirname, '\\');
+- if (unescape)
+- end_name = strchr (unescape, '\0');
+- }
+- else
+- unescape = memchr (dirname, '\\', end_name - dirname);
+- }
+- if (end_name == NULL)
+- user_name = dirname + 1;
+- else
+- {
+- char *newp;
+- if (glob_use_alloca (alloca_used, end_name - dirname))
+- newp = alloca_account (end_name - dirname, alloca_used);
+- else
+- {
+- newp = malloc (end_name - dirname);
+- if (newp == NULL)
+- {
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+- malloc_user_name = 1;
+- }
+- if (unescape != NULL)
+- {
+- char *p = mempcpy (newp, dirname + 1,
+- unescape - dirname - 1);
+- char *q = unescape;
+- while (q != end_name)
+- {
+- if (*q == '\\')
+- {
+- if (q + 1 == end_name)
+- {
+- /* "~fo\\o\\" unescape to user_name "foo\\",
+- but "~fo\\o\\/" unescape to user_name
+- "foo". */
+- if (filename == NULL)
+- *p++ = '\\';
+- break;
+- }
+- ++q;
+- }
+- *p++ = *q++;
+- }
+- *p = '\0';
+- }
+- else
+- *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1))
+- = '\0';
+- user_name = newp;
+- }
+-
+- /* Look up specific user's home directory. */
+- {
+- struct passwd *p;
+- struct scratch_buffer pwtmpbuf;
+- scratch_buffer_init (&pwtmpbuf);
++ /* Recognize ~user as a shorthand for the specified user's home
++ directory. */
++ char *end_name = strchr (dirname, '/');
++ char *user_name;
++ int malloc_user_name = 0;
++ char *unescape = NULL;
++
++ if (!(flags & GLOB_NOESCAPE))
++ {
++ if (end_name == NULL)
++ {
++ unescape = strchr (dirname, '\\');
++ if (unescape)
++ end_name = strchr (unescape, '\0');
++ }
++ else
++ unescape = memchr (dirname, '\\', end_name - dirname);
++ }
++ if (end_name == NULL)
++ user_name = dirname + 1;
++ else
++ {
++ char *newp;
++ if (glob_use_alloca (alloca_used, end_name - dirname))
++ newp = alloca_account (end_name - dirname, alloca_used);
++ else
++ {
++ newp = malloc (end_name - dirname);
++ if (newp == NULL)
++ {
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
++ malloc_user_name = 1;
++ }
++ if (unescape != NULL)
++ {
++ char *p = mempcpy (newp, dirname + 1,
++ unescape - dirname - 1);
++ char *q = unescape;
++ while (q != end_name)
++ {
++ if (*q == '\\')
++ {
++ if (q + 1 == end_name)
++ {
++ /* "~fo\\o\\" unescape to user_name "foo\\",
++ but "~fo\\o\\/" unescape to user_name
++ "foo". */
++ if (filename == NULL)
++ *p++ = '\\';
++ break;
++ }
++ ++q;
++ }
++ *p++ = *q++;
++ }
++ *p = '\0';
++ }
++ else
++ *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1))
++ = '\0';
++ user_name = newp;
++ }
++
++ /* Look up specific user's home directory. */
++ {
++ struct passwd *p;
++ struct scratch_buffer pwtmpbuf;
++ scratch_buffer_init (&pwtmpbuf);
+
+ # if defined HAVE_GETPWNAM_R || defined _LIBC
+- struct passwd pwbuf;
++ struct passwd pwbuf;
+
+- while (getpwnam_r (user_name, &pwbuf,
+- pwtmpbuf.data, pwtmpbuf.length, &p)
+- == ERANGE)
+- {
+- if (!scratch_buffer_grow (&pwtmpbuf))
+- {
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+- }
++ while (getpwnam_r (user_name, &pwbuf,
++ pwtmpbuf.data, pwtmpbuf.length, &p)
++ == ERANGE)
++ {
++ if (!scratch_buffer_grow (&pwtmpbuf))
++ {
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
++ }
+ # else
+- p = getpwnam (user_name);
++ p = getpwnam (user_name);
+ # endif
+
+- if (__glibc_unlikely (malloc_user_name))
+- free (user_name);
++ if (__glibc_unlikely (malloc_user_name))
++ free (user_name);
+
+- /* If we found a home directory use this. */
+- if (p != NULL)
+- {
+- size_t home_len = strlen (p->pw_dir);
+- size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+- char *d, *newp;
+- bool use_alloca = glob_use_alloca (alloca_used,
+- home_len + rest_len + 1);
+-
+- if (use_alloca)
+- newp = alloca_account (home_len + rest_len + 1, alloca_used);
+- else
+- {
+- newp = malloc (home_len + rest_len + 1);
+- if (newp == NULL)
+- {
+- scratch_buffer_free (&pwtmpbuf);
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+- }
+- d = mempcpy (newp, p->pw_dir, home_len);
+- if (end_name != NULL)
+- d = mempcpy (d, end_name, rest_len);
+- *d = '\0';
+-
+- if (__glibc_unlikely (malloc_dirname))
+- free (dirname);
+- dirname = newp;
+- malloc_dirname = !use_alloca;
+-
+- dirlen = home_len + rest_len;
+- dirname_modified = 1;
+- }
+- else
+- {
+- if (flags & GLOB_TILDE_CHECK)
+- {
+- /* We have to regard it as an error if we cannot find the
+- home directory. */
+- retval = GLOB_NOMATCH;
+- goto out;
+- }
+- }
+- scratch_buffer_free (&pwtmpbuf);
+- }
+-#endif /* !WINDOWS32 */
+- }
++ /* If we found a home directory use this. */
++ if (p != NULL)
++ {
++ size_t home_len = strlen (p->pw_dir);
++ size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
++ /* dirname contains end_name; we can't free it now. */
++ char *prev_dirname =
++ (__glibc_unlikely (malloc_dirname) ? dirname : NULL);
++ char *d;
++
++ malloc_dirname = 0;
++
++ if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
++ dirname = alloca_account (home_len + rest_len + 1,
++ alloca_used);
++ else
++ {
++ dirname = malloc (home_len + rest_len + 1);
++ if (dirname == NULL)
++ {
++ free (prev_dirname);
++ scratch_buffer_free (&pwtmpbuf);
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
++ malloc_dirname = 1;
++ }
++ d = mempcpy (dirname, p->pw_dir, home_len);
++ if (end_name != NULL)
++ d = mempcpy (d, end_name, rest_len);
++ *d = '\0';
++
++ free (prev_dirname);
++
++ dirlen = home_len + rest_len;
++ dirname_modified = 1;
++ }
++ else
++ {
++ if (flags & GLOB_TILDE_CHECK)
++ {
++ /* We have to regard it as an error if we cannot find the
++ home directory. */
++ retval = GLOB_NOMATCH;
++ goto out;
++ }
++ }
++ scratch_buffer_free (&pwtmpbuf);
++ }
++#else /* WINDOWS32 */
++ /* On native Windows, access to a user's home directory
++ (via GetUserProfileDirectory) or to a user's environment
++ variables (via ExpandEnvironmentStringsForUser) requires
++ the credentials of the user. Therefore we cannot support
++ the ~user syntax on this platform.
++ Handling ~user specially (and treat it like plain ~) if
++ user is getenv ("USERNAME") would not be a good idea,
++ since it would make people think that ~user is supported
++ in general. */
++ if (flags & GLOB_TILDE_CHECK)
++ {
++ retval = GLOB_NOMATCH;
++ goto out;
++ }
++#endif /* WINDOWS32 */
++ }
+ }
+
+ /* Now test whether we looked for "~" or "~NAME". In this case we
+ can give the answer now. */
+ if (filename == NULL)
+ {
+- size_t newcount = pglob->gl_pathc + pglob->gl_offs;
+- char **new_gl_pathv;
++ size_t newcount = pglob->gl_pathc + pglob->gl_offs;
++ char **new_gl_pathv;
++
++ if (newcount > SIZE_MAX / sizeof (char *) - 2)
++ {
++ nospace:
++ free (pglob->gl_pathv);
++ pglob->gl_pathv = NULL;
++ pglob->gl_pathc = 0;
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
+
+- if (newcount > SIZE_MAX / sizeof (char *) - 2)
+- {
+- nospace:
+- free (pglob->gl_pathv);
+- pglob->gl_pathv = NULL;
+- pglob->gl_pathc = 0;
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+-
+- new_gl_pathv = realloc (pglob->gl_pathv,
+- (newcount + 2) * sizeof (char *));
+- if (new_gl_pathv == NULL)
+- goto nospace;
+- pglob->gl_pathv = new_gl_pathv;
+-
+- if (flags & GLOB_MARK && is_dir (dirname, flags, pglob))
+- {
+- char *p;
+- pglob->gl_pathv[newcount] = malloc (dirlen + 2);
+- if (pglob->gl_pathv[newcount] == NULL)
+- goto nospace;
+- p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
+- p[0] = '/';
+- p[1] = '\0';
+- if (__glibc_unlikely (malloc_dirname))
+- free (dirname);
+- }
+- else
+- {
+- if (__glibc_unlikely (malloc_dirname))
+- pglob->gl_pathv[newcount] = dirname;
+- else
+- {
+- pglob->gl_pathv[newcount] = strdup (dirname);
+- if (pglob->gl_pathv[newcount] == NULL)
+- goto nospace;
+- }
+- }
+- pglob->gl_pathv[++newcount] = NULL;
+- ++pglob->gl_pathc;
+- pglob->gl_flags = flags;
++ new_gl_pathv = realloc (pglob->gl_pathv,
++ (newcount + 2) * sizeof (char *));
++ if (new_gl_pathv == NULL)
++ goto nospace;
++ pglob->gl_pathv = new_gl_pathv;
++
++ if (flags & GLOB_MARK && is_dir (dirname, flags, pglob))
++ {
++ char *p;
++ pglob->gl_pathv[newcount] = malloc (dirlen + 2);
++ if (pglob->gl_pathv[newcount] == NULL)
++ goto nospace;
++ p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
++ p[0] = '/';
++ p[1] = '\0';
++ if (__glibc_unlikely (malloc_dirname))
++ free (dirname);
++ }
++ else
++ {
++ if (__glibc_unlikely (malloc_dirname))
++ pglob->gl_pathv[newcount] = dirname;
++ else
++ {
++ pglob->gl_pathv[newcount] = strdup (dirname);
++ if (pglob->gl_pathv[newcount] == NULL)
++ goto nospace;
++ }
++ }
++ pglob->gl_pathv[++newcount] = NULL;
++ ++pglob->gl_pathc;
++ pglob->gl_flags = flags;
+
+- return 0;
++ return 0;
+ }
+
+ meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
+@@ -934,135 +969,135 @@ __glob (const char *pattern, int flags,
+ if (meta & (GLOBPAT_SPECIAL | GLOBPAT_BRACKET))
+ {
+ /* The directory name contains metacharacters, so we
+- have to glob for the directory, and then glob for
+- the pattern in each directory found. */
++ have to glob for the directory, and then glob for
++ the pattern in each directory found. */
+ size_t i;
+
+ if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\')
+- {
+- /* "foo\\/bar". Remove the final backslash from dirname
+- if it has not been quoted. */
+- char *p = (char *) &dirname[dirlen - 1];
+-
+- while (p > dirname && p[-1] == '\\') --p;
+- if ((&dirname[dirlen] - p) & 1)
+- *(char *) &dirname[--dirlen] = '\0';
+- }
++ {
++ /* "foo\\/bar". Remove the final backslash from dirname
++ if it has not been quoted. */
++ char *p = (char *) &dirname[dirlen - 1];
++
++ while (p > dirname && p[-1] == '\\') --p;
++ if ((&dirname[dirlen] - p) & 1)
++ *(char *) &dirname[--dirlen] = '\0';
++ }
+
+ if (__glibc_unlikely ((flags & GLOB_ALTDIRFUNC) != 0))
+- {
+- /* Use the alternative access functions also in the recursive
+- call. */
+- dirs.gl_opendir = pglob->gl_opendir;
+- dirs.gl_readdir = pglob->gl_readdir;
+- dirs.gl_closedir = pglob->gl_closedir;
+- dirs.gl_stat = pglob->gl_stat;
+- dirs.gl_lstat = pglob->gl_lstat;
+- }
++ {
++ /* Use the alternative access functions also in the recursive
++ call. */
++ dirs.gl_opendir = pglob->gl_opendir;
++ dirs.gl_readdir = pglob->gl_readdir;
++ dirs.gl_closedir = pglob->gl_closedir;
++ dirs.gl_stat = pglob->gl_stat;
++ dirs.gl_lstat = pglob->gl_lstat;
++ }
+
+ status = __glob (dirname,
+- ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC))
+- | GLOB_NOSORT | GLOB_ONLYDIR),
+- errfunc, &dirs);
++ ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC))
++ | GLOB_NOSORT | GLOB_ONLYDIR),
++ errfunc, &dirs);
+ if (status != 0)
+- {
+- if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
+- {
+- retval = status;
+- goto out;
+- }
+- goto no_matches;
+- }
++ {
++ if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
++ {
++ retval = status;
++ goto out;
++ }
++ goto no_matches;
++ }
+
+ /* We have successfully globbed the preceding directory name.
+- For each name we found, call glob_in_dir on it and FILENAME,
+- appending the results to PGLOB. */
++ For each name we found, call glob_in_dir on it and FILENAME,
++ appending the results to PGLOB. */
+ for (i = 0; i < dirs.gl_pathc; ++i)
+- {
+- size_t old_pathc;
++ {
++ size_t old_pathc;
+
+- old_pathc = pglob->gl_pathc;
+- status = glob_in_dir (filename, dirs.gl_pathv[i],
+- ((flags | GLOB_APPEND)
+- & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
+- errfunc, pglob, alloca_used);
+- if (status == GLOB_NOMATCH)
+- /* No matches in this directory. Try the next. */
+- continue;
+-
+- if (status != 0)
+- {
+- globfree (&dirs);
+- globfree (pglob);
+- pglob->gl_pathc = 0;
+- retval = status;
+- goto out;
+- }
+-
+- /* Stick the directory on the front of each name. */
+- if (prefix_array (dirs.gl_pathv[i],
+- &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+- pglob->gl_pathc - old_pathc))
+- {
+- globfree (&dirs);
+- globfree (pglob);
+- pglob->gl_pathc = 0;
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+- }
++ old_pathc = pglob->gl_pathc;
++ status = glob_in_dir (filename, dirs.gl_pathv[i],
++ ((flags | GLOB_APPEND)
++ & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
++ errfunc, pglob, alloca_used);
++ if (status == GLOB_NOMATCH)
++ /* No matches in this directory. Try the next. */
++ continue;
++
++ if (status != 0)
++ {
++ globfree (&dirs);
++ globfree (pglob);
++ pglob->gl_pathc = 0;
++ retval = status;
++ goto out;
++ }
++
++ /* Stick the directory on the front of each name. */
++ if (prefix_array (dirs.gl_pathv[i],
++ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
++ pglob->gl_pathc - old_pathc))
++ {
++ globfree (&dirs);
++ globfree (pglob);
++ pglob->gl_pathc = 0;
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
++ }
+
+ flags |= GLOB_MAGCHAR;
+
+ /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls.
+- But if we have not found any matching entry and the GLOB_NOCHECK
+- flag was set we must return the input pattern itself. */
++ But if we have not found any matching entry and the GLOB_NOCHECK
++ flag was set we must return the input pattern itself. */
+ if (pglob->gl_pathc + pglob->gl_offs == oldcount)
+- {
+- no_matches:
+- /* No matches. */
+- if (flags & GLOB_NOCHECK)
+- {
+- size_t newcount = pglob->gl_pathc + pglob->gl_offs;
+- char **new_gl_pathv;
+-
+- if (newcount > SIZE_MAX / sizeof (char *) - 2)
+- {
+- nospace2:
+- globfree (&dirs);
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+-
+- new_gl_pathv = realloc (pglob->gl_pathv,
+- (newcount + 2) * sizeof (char *));
+- if (new_gl_pathv == NULL)
+- goto nospace2;
+- pglob->gl_pathv = new_gl_pathv;
+-
+- pglob->gl_pathv[newcount] = strdup (pattern);
+- if (pglob->gl_pathv[newcount] == NULL)
+- {
+- globfree (&dirs);
+- globfree (pglob);
+- pglob->gl_pathc = 0;
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+-
+- ++pglob->gl_pathc;
+- ++newcount;
+-
+- pglob->gl_pathv[newcount] = NULL;
+- pglob->gl_flags = flags;
+- }
+- else
+- {
+- globfree (&dirs);
+- retval = GLOB_NOMATCH;
+- goto out;
+- }
+- }
++ {
++ no_matches:
++ /* No matches. */
++ if (flags & GLOB_NOCHECK)
++ {
++ size_t newcount = pglob->gl_pathc + pglob->gl_offs;
++ char **new_gl_pathv;
++
++ if (newcount > SIZE_MAX / sizeof (char *) - 2)
++ {
++ nospace2:
++ globfree (&dirs);
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
++
++ new_gl_pathv = realloc (pglob->gl_pathv,
++ (newcount + 2) * sizeof (char *));
++ if (new_gl_pathv == NULL)
++ goto nospace2;
++ pglob->gl_pathv = new_gl_pathv;
++
++ pglob->gl_pathv[newcount] = strdup (pattern);
++ if (pglob->gl_pathv[newcount] == NULL)
++ {
++ globfree (&dirs);
++ globfree (pglob);
++ pglob->gl_pathc = 0;
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
++
++ ++pglob->gl_pathc;
++ ++newcount;
++
++ pglob->gl_pathv[newcount] = NULL;
++ pglob->gl_flags = flags;
++ }
++ else
++ {
++ globfree (&dirs);
++ retval = GLOB_NOMATCH;
++ goto out;
++ }
++ }
+
+ globfree (&dirs);
+ }
+@@ -1072,57 +1107,57 @@ __glob (const char *pattern, int flags,
+ int orig_flags = flags;
+
+ if (meta & GLOBPAT_BACKSLASH)
+- {
+- char *p = strchr (dirname, '\\'), *q;
+- /* We need to unescape the dirname string. It is certainly
+- allocated by alloca, as otherwise filename would be NULL
+- or dirname wouldn't contain backslashes. */
+- q = p;
+- do
+- {
+- if (*p == '\\')
+- {
+- *q = *++p;
+- --dirlen;
+- }
+- else
+- *q = *p;
+- ++q;
+- }
+- while (*p++ != '\0');
+- dirname_modified = 1;
+- }
++ {
++ char *p = strchr (dirname, '\\'), *q;
++ /* We need to unescape the dirname string. It is certainly
++ allocated by alloca, as otherwise filename would be NULL
++ or dirname wouldn't contain backslashes. */
++ q = p;
++ do
++ {
++ if (*p == '\\')
++ {
++ *q = *++p;
++ --dirlen;
++ }
++ else
++ *q = *p;
++ ++q;
++ }
++ while (*p++ != '\0');
++ dirname_modified = 1;
++ }
+ if (dirname_modified)
+- flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
++ flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
+ status = glob_in_dir (filename, dirname, flags, errfunc, pglob,
+- alloca_used);
++ alloca_used);
+ if (status != 0)
+- {
+- if (status == GLOB_NOMATCH && flags != orig_flags
+- && pglob->gl_pathc + pglob->gl_offs == oldcount)
+- {
+- /* Make sure globfree (&dirs); is a nop. */
+- dirs.gl_pathv = NULL;
+- flags = orig_flags;
+- goto no_matches;
+- }
+- retval = status;
+- goto out;
+- }
++ {
++ if (status == GLOB_NOMATCH && flags != orig_flags
++ && pglob->gl_pathc + pglob->gl_offs == oldcount)
++ {
++ /* Make sure globfree (&dirs); is a nop. */
++ dirs.gl_pathv = NULL;
++ flags = orig_flags;
++ goto no_matches;
++ }
++ retval = status;
++ goto out;
++ }
+
+ if (dirlen > 0)
+- {
+- /* Stick the directory on the front of each name. */
+- if (prefix_array (dirname,
+- &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+- pglob->gl_pathc - old_pathc))
+- {
+- globfree (pglob);
+- pglob->gl_pathc = 0;
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+- }
++ {
++ /* Stick the directory on the front of each name. */
++ if (prefix_array (dirname,
++ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
++ pglob->gl_pathc - old_pathc))
++ {
++ globfree (pglob);
++ pglob->gl_pathc = 0;
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
++ }
+ }
+
+ if (flags & GLOB_MARK)
+@@ -1131,28 +1166,28 @@ __glob (const char *pattern, int flags,
+ size_t i;
+
+ for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i)
+- if (is_dir (pglob->gl_pathv[i], flags, pglob))
+- {
+- size_t len = strlen (pglob->gl_pathv[i]) + 2;
+- char *new = realloc (pglob->gl_pathv[i], len);
+- if (new == NULL)
+- {
+- globfree (pglob);
+- pglob->gl_pathc = 0;
+- retval = GLOB_NOSPACE;
+- goto out;
+- }
+- strcpy (&new[len - 2], "/");
+- pglob->gl_pathv[i] = new;
+- }
++ if (is_dir (pglob->gl_pathv[i], flags, pglob))
++ {
++ size_t len = strlen (pglob->gl_pathv[i]) + 2;
++ char *new = realloc (pglob->gl_pathv[i], len);
++ if (new == NULL)
++ {
++ globfree (pglob);
++ pglob->gl_pathc = 0;
++ retval = GLOB_NOSPACE;
++ goto out;
++ }
++ strcpy (&new[len - 2], "/");
++ pglob->gl_pathv[i] = new;
++ }
+ }
+
+ if (!(flags & GLOB_NOSORT))
+ {
+ /* Sort the vector. */
+ qsort (&pglob->gl_pathv[oldcount],
+- pglob->gl_pathc + pglob->gl_offs - oldcount,
+- sizeof (char *), collated_compare);
++ pglob->gl_pathc + pglob->gl_offs - oldcount,
++ sizeof (char *), collated_compare);
+ }
+
+ out:
+@@ -1204,14 +1239,14 @@ prefix_array (const char *dirname, char
+ if (dirlen > 1)
+ {
+ if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
+- /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */
+- --dirlen;
++ /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */
++ --dirlen;
+ else if (dirname[dirlen - 1] == ':')
+- {
+- /* DIRNAME is "d:". Use ':' instead of '/'. */
+- --dirlen;
+- dirsep_char = ':';
+- }
++ {
++ /* DIRNAME is "d:". Use ':' instead of '/'. */
++ --dirlen;
++ dirsep_char = ':';
++ }
+ }
+ #endif
+
+@@ -1220,16 +1255,16 @@ prefix_array (const char *dirname, char
+ size_t eltlen = strlen (array[i]) + 1;
+ char *new = malloc (dirlen + 1 + eltlen);
+ if (new == NULL)
+- {
+- while (i > 0)
+- free (array[--i]);
+- return 1;
+- }
++ {
++ while (i > 0)
++ free (array[--i]);
++ return 1;
++ }
+
+ {
+- char *endp = mempcpy (new, dirname, dirlen);
+- *endp++ = dirsep_char;
+- mempcpy (endp, array[i], eltlen);
++ char *endp = mempcpy (new, dirname, dirlen);
++ *endp++ = dirsep_char;
++ mempcpy (endp, array[i], eltlen);
+ }
+ free (array[i]);
+ array[i] = new;
+@@ -1244,11 +1279,13 @@ prefix_array (const char *dirname, char
+ The GLOB_APPEND flag is assumed to be set (always appends). */
+ static int
+ glob_in_dir (const char *pattern, const char *directory, int flags,
+- int (*errfunc) (const char *, int),
+- glob_t *pglob, size_t alloca_used)
++ int (*errfunc) (const char *, int),
++ glob_t *pglob, size_t alloca_used)
+ {
+ size_t dirlen = strlen (directory);
+ void *stream = NULL;
++ struct scratch_buffer s;
++ scratch_buffer_init (&s);
+ # define GLOBNAMES_MEMBERS(nnames) \
+ struct globnames *next; size_t count; char *name[nnames];
+ struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) };
+@@ -1273,8 +1310,8 @@ glob_in_dir (const char *pattern, const
+ if (meta == GLOBPAT_NONE && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+ {
+ /* We need not do any tests. The PATTERN contains no meta
+- characters and we must not return an error therefore the
+- result will always contain exactly one name. */
++ characters and we must not return an error therefore the
++ result will always contain exactly one name. */
+ flags |= GLOB_NOCHECK;
+ }
+ else if (meta == GLOBPAT_NONE)
+@@ -1288,102 +1325,127 @@ glob_in_dir (const char *pattern, const
+ if (alloca_fullname)
+ fullname = alloca_account (fullsize, alloca_used);
+ else
+- {
+- fullname = malloc (fullsize);
+- if (fullname == NULL)
+- return GLOB_NOSPACE;
+- }
++ {
++ fullname = malloc (fullsize);
++ if (fullname == NULL)
++ return GLOB_NOSPACE;
++ }
+
+ mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
+- "/", 1),
+- pattern, patlen + 1);
++ "/", 1),
++ pattern, patlen + 1);
+ if (glob_lstat (pglob, flags, fullname) == 0
+- || errno == EOVERFLOW)
+- /* We found this file to be existing. Now tell the rest
+- of the function to copy this name into the result. */
+- flags |= GLOB_NOCHECK;
++ || errno == EOVERFLOW)
++ /* We found this file to be existing. Now tell the rest
++ of the function to copy this name into the result. */
++ flags |= GLOB_NOCHECK;
+
+ if (__glibc_unlikely (!alloca_fullname))
+- free (fullname);
++ free (fullname);
+ }
+ else
+ {
+ stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+- ? (*pglob->gl_opendir) (directory)
+- : opendir (directory));
++ ? (*pglob->gl_opendir) (directory)
++ : opendir (directory));
+ if (stream == NULL)
+- {
+- if (errno != ENOTDIR
+- && ((errfunc != NULL && (*errfunc) (directory, errno))
+- || (flags & GLOB_ERR)))
+- return GLOB_ABORTED;
+- }
++ {
++ if (errno != ENOTDIR
++ && ((errfunc != NULL && (*errfunc) (directory, errno))
++ || (flags & GLOB_ERR)))
++ return GLOB_ABORTED;
++ }
+ else
+- {
+- int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
+- | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
+- flags |= GLOB_MAGCHAR;
+-
+- while (1)
+- {
+- struct readdir_result d;
+- {
+- if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+- d = convert_dirent (GL_READDIR (pglob, stream));
+- else
+- {
++ {
++ int dfd = dirfd (stream);
++ int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
++ | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
++ flags |= GLOB_MAGCHAR;
++
++ while (1)
++ {
++ struct readdir_result d;
++ {
++ if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
++ d = convert_dirent (GL_READDIR (pglob, stream));
++ else
++ {
+ #ifdef COMPILE_GLOB64
+- d = convert_dirent (__readdir (stream));
++ d = convert_dirent (__readdir (stream));
+ #else
+- d = convert_dirent64 (__readdir64 (stream));
++ d = convert_dirent64 (__readdir64 (stream));
+ #endif
+- }
+- }
+- if (d.name == NULL)
+- break;
+-
+- /* If we shall match only directories use the information
+- provided by the dirent call if possible. */
+- if (flags & GLOB_ONLYDIR)
+- switch (readdir_result_type (d))
+- {
+- case DT_DIR: case DT_LNK: case DT_UNKNOWN: break;
+- default: continue;
+- }
+-
+- if (fnmatch (pattern, d.name, fnm_flags) == 0)
+- {
+- if (cur == names->count)
+- {
+- struct globnames *newnames;
+- size_t count = names->count * 2;
+- size_t nameoff = offsetof (struct globnames, name);
+- size_t size = FLEXSIZEOF (struct globnames, name,
+- count * sizeof (char *));
+- if ((SIZE_MAX - nameoff) / 2 / sizeof (char *)
+- < names->count)
+- goto memory_error;
+- if (glob_use_alloca (alloca_used, size))
+- newnames = names_alloca
+- = alloca_account (size, alloca_used);
+- else if ((newnames = malloc (size))
+- == NULL)
+- goto memory_error;
+- newnames->count = count;
+- newnames->next = names;
+- names = newnames;
+- cur = 0;
+- }
+- names->name[cur] = strdup (d.name);
+- if (names->name[cur] == NULL)
+- goto memory_error;
+- ++cur;
+- ++nfound;
+- if (SIZE_MAX - pglob->gl_offs <= nfound)
+- goto memory_error;
+- }
+- }
+- }
++ }
++ }
++ if (d.name == NULL)
++ break;
++
++ /* If we shall match only directories use the information
++ provided by the dirent call if possible. */
++ if (flags & GLOB_ONLYDIR)
++ switch (readdir_result_type (d))
++ {
++ default: continue;
++ case DT_DIR: break;
++ case DT_LNK: case DT_UNKNOWN:
++ /* The filesystem was too lazy to give us a hint,
++ so we have to do it the hard way. */
++ if (__glibc_unlikely (dfd < 0 || flags & GLOB_ALTDIRFUNC))
++ {
++ size_t namelen = strlen (d.name);
++ size_t need = dirlen + 1 + namelen + 1;
++ if (s.length < need
++ && !scratch_buffer_set_array_size (&s, need, 1))
++ goto memory_error;
++ char *p = mempcpy (s.data, directory, dirlen);
++ *p = '/';
++ p += p[-1] != '/';
++ memcpy (p, d.name, namelen + 1);
++ if (! is_dir (s.data, flags, pglob))
++ continue;
++ }
++ else
++ {
++ struct_stat64 st64;
++ if (! (GLOB_FSTATAT64 (dfd, d.name, &st64, 0) == 0
++ && S_ISDIR (st64.st_mode)))
++ continue;
++ }
++ }
++
++ if (fnmatch (pattern, d.name, fnm_flags) == 0)
++ {
++ if (cur == names->count)
++ {
++ struct globnames *newnames;
++ size_t count = names->count * 2;
++ size_t nameoff = offsetof (struct globnames, name);
++ size_t size = FLEXSIZEOF (struct globnames, name,
++ count * sizeof (char *));
++ if ((SIZE_MAX - nameoff) / 2 / sizeof (char *)
++ < names->count)
++ goto memory_error;
++ if (glob_use_alloca (alloca_used, size))
++ newnames = names_alloca
++ = alloca_account (size, alloca_used);
++ else if ((newnames = malloc (size))
++ == NULL)
++ goto memory_error;
++ newnames->count = count;
++ newnames->next = names;
++ names = newnames;
++ cur = 0;
++ }
++ names->name[cur] = strdup (d.name);
++ if (names->name[cur] == NULL)
++ goto memory_error;
++ ++cur;
++ ++nfound;
++ if (SIZE_MAX - pglob->gl_offs <= nfound)
++ goto memory_error;
++ }
++ }
++ }
+ }
+
+ if (nfound == 0 && (flags & GLOB_NOCHECK))
+@@ -1392,7 +1454,7 @@ glob_in_dir (const char *pattern, const
+ nfound = 1;
+ names->name[cur] = malloc (len + 1);
+ if (names->name[cur] == NULL)
+- goto memory_error;
++ goto memory_error;
+ *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
+ }
+
+@@ -1403,82 +1465,83 @@ glob_in_dir (const char *pattern, const
+ result = 0;
+
+ if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc
+- < pglob->gl_offs + nfound + 1)
+- goto memory_error;
++ < pglob->gl_offs + nfound + 1)
++ goto memory_error;
+
+ new_gl_pathv
+- = realloc (pglob->gl_pathv,
+- (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+- * sizeof (char *));
++ = realloc (pglob->gl_pathv,
++ (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
++ * sizeof (char *));
+
+ if (new_gl_pathv == NULL)
+- {
+- memory_error:
+- while (1)
+- {
+- struct globnames *old = names;
+- for (size_t i = 0; i < cur; ++i)
+- free (names->name[i]);
+- names = names->next;
+- /* NB: we will not leak memory here if we exit without
+- freeing the current block assigned to OLD. At least
+- the very first block is always allocated on the stack
+- and this is the block assigned to OLD here. */
+- if (names == NULL)
+- {
+- assert (old == init_names);
+- break;
+- }
+- cur = names->count;
+- if (old == names_alloca)
+- names_alloca = names;
+- else
+- free (old);
+- }
+- result = GLOB_NOSPACE;
+- }
++ {
++ memory_error:
++ while (1)
++ {
++ struct globnames *old = names;
++ for (size_t i = 0; i < cur; ++i)
++ free (names->name[i]);
++ names = names->next;
++ /* NB: we will not leak memory here if we exit without
++ freeing the current block assigned to OLD. At least
++ the very first block is always allocated on the stack
++ and this is the block assigned to OLD here. */
++ if (names == NULL)
++ {
++ assert (old == init_names);
++ break;
++ }
++ cur = names->count;
++ if (old == names_alloca)
++ names_alloca = names;
++ else
++ free (old);
++ }
++ result = GLOB_NOSPACE;
++ }
+ else
+- {
+- while (1)
+- {
+- struct globnames *old = names;
+- for (size_t i = 0; i < cur; ++i)
+- new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++]
+- = names->name[i];
+- names = names->next;
+- /* NB: we will not leak memory here if we exit without
+- freeing the current block assigned to OLD. At least
+- the very first block is always allocated on the stack
+- and this is the block assigned to OLD here. */
+- if (names == NULL)
+- {
+- assert (old == init_names);
+- break;
+- }
+- cur = names->count;
+- if (old == names_alloca)
+- names_alloca = names;
+- else
+- free (old);
+- }
++ {
++ while (1)
++ {
++ struct globnames *old = names;
++ for (size_t i = 0; i < cur; ++i)
++ new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++]
++ = names->name[i];
++ names = names->next;
++ /* NB: we will not leak memory here if we exit without
++ freeing the current block assigned to OLD. At least
++ the very first block is always allocated on the stack
++ and this is the block assigned to OLD here. */
++ if (names == NULL)
++ {
++ assert (old == init_names);
++ break;
++ }
++ cur = names->count;
++ if (old == names_alloca)
++ names_alloca = names;
++ else
++ free (old);
++ }
+
+- pglob->gl_pathv = new_gl_pathv;
++ pglob->gl_pathv = new_gl_pathv;
+
+- pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
++ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+- pglob->gl_flags = flags;
+- }
++ pglob->gl_flags = flags;
++ }
+ }
+
+ if (stream != NULL)
+ {
+ save = errno;
+ if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC))
+- (*pglob->gl_closedir) (stream);
++ (*pglob->gl_closedir) (stream);
+ else
+- closedir (stream);
++ closedir (stream);
+ __set_errno (save);
+ }
+
++ scratch_buffer_free (&s);
+ return result;
+ }
+diff -rup a/sysdeps/gnu/glob-lstat-compat.c b/sysdeps/gnu/glob-lstat-compat.c
+--- a/sysdeps/gnu/glob-lstat-compat.c 2018-08-01 01:10:47.000000000 -0400
++++ b/sysdeps/gnu/glob-lstat-compat.c 2022-05-02 17:51:04.167557574 -0400
+@@ -29,7 +29,8 @@
+ #define GLOB_ATTRIBUTE attribute_compat_text_section
+
+ /* Avoid calling gl_lstat with GLOB_ALTDIRFUNC. */
+-#define GLOB_NO_LSTAT
++#define GLOB_LSTAT gl_stat
++#define GLOB_LSTAT64 __stat64
+
+ #include
+
+diff -rup a/sysdeps/unix/sysv/linux/glob-lstat-compat.c b/sysdeps/unix/sysv/linux/glob-lstat-compat.c
+--- a/sysdeps/unix/sysv/linux/glob-lstat-compat.c 2018-08-01 01:10:47.000000000 -0400
++++ b/sysdeps/unix/sysv/linux/glob-lstat-compat.c 2022-05-02 23:05:45.197297341 -0400
+@@ -30,7 +30,12 @@
+ #define GLOB_ATTRIBUTE attribute_compat_text_section
+
+ /* Avoid calling gl_lstat with GLOB_ALTDIRFUNC. */
+-#define GLOB_NO_LSTAT
++# define COMPILE_GLOB64 1
++# define struct_stat struct stat
++# define struct_stat64 struct stat64
++# define GLOB_LSTAT gl_stat
++# define GLOB_STAT64 __stat64
++# define GLOB_LSTAT64 __stat64
+
+ #include
+
diff --git a/glibc-rh2033684-1.patch b/glibc-rh2033684-1.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8734628d6447ba9501ee0e3dee67ec02684a113d
--- /dev/null
+++ b/glibc-rh2033684-1.patch
@@ -0,0 +1,27 @@
+commit 2a08b6e8331a611dc29325bfa6e29fecc9a3a46e
+Author: Siddhesh Poyarekar
+Date: Thu Dec 10 16:47:02 2020 +0530
+
+ Warn on unsupported fortification levels
+
+ Make the _FORTIFY_SOURCE macro soup in features.h warn about
+ unsupported fortification levels. For example, it will warn about
+ _FORTIFY_SOURCE=3 and over with an indication of which level has been
+ selected.
+
+ Co-authored-by: Paul Eggert
+
+diff --git a/include/features.h b/include/features.h
+index 5bed0a499605a3a2..ea7673ee115bcf0a 100644
+--- a/include/features.h
++++ b/include/features.h
+@@ -382,6 +382,9 @@
+ # elif !__GNUC_PREREQ (4, 1)
+ # warning _FORTIFY_SOURCE requires GCC 4.1 or later
+ # elif _FORTIFY_SOURCE > 1
++# if _FORTIFY_SOURCE > 2
++# warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform
++# endif
+ # define __USE_FORTIFY_LEVEL 2
+ # else
+ # define __USE_FORTIFY_LEVEL 1
diff --git a/glibc-rh2033684-10.patch b/glibc-rh2033684-10.patch
new file mode 100644
index 0000000000000000000000000000000000000000..94b45192c0c2e596452976ac8d5a2f4fe5f0b33d
--- /dev/null
+++ b/glibc-rh2033684-10.patch
@@ -0,0 +1,90 @@
+commit 2bbd07c715275eb6c616988925738a0517180d57
+Author: Siddhesh Poyarekar
+Date: Fri Dec 17 18:35:44 2021 +0530
+
+ fortify: Fix spurious warning with realpath
+
+ The length and object size arguments were swapped around for realpath.
+ Also add a smoke test so that any changes in this area get caught in
+ future.
+
+ Signed-off-by: Siddhesh Poyarekar
+ Reviewed-by: Adhemerval Zanella
+
+diff --git a/debug/Makefile b/debug/Makefile
+index 81361438fc3d2aa9..b43f42ee3851f360 100644
+--- a/debug/Makefile
++++ b/debug/Makefile
+@@ -108,6 +108,7 @@ CFLAGS-tst-longjmp_chk2.c += -fexceptions -fasynchronous-unwind-tables
+ CPPFLAGS-tst-longjmp_chk2.c += -D_FORTIFY_SOURCE=1
+ CFLAGS-tst-longjmp_chk3.c += -fexceptions -fasynchronous-unwind-tables
+ CPPFLAGS-tst-longjmp_chk3.c += -D_FORTIFY_SOURCE=1
++CPPFLAGS-tst-realpath-chk.c += -D_FORTIFY_SOURCE=2
+
+ # We know these tests have problems with format strings, this is what
+ # we are testing. Disable that warning. They are also testing
+@@ -155,7 +156,7 @@ tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \
+ tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \
+ tst-chk4 tst-chk5 tst-chk6 tst-chk7 tst-chk8 tst-lfschk4 tst-lfschk5 \
+ tst-lfschk6 tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 \
+- tst-backtrace4 tst-backtrace5 tst-backtrace6
++ tst-backtrace4 tst-backtrace5 tst-backtrace6 tst-realpath-chk
+
+ ifeq ($(have-ssp),yes)
+ tests += tst-ssp-1
+diff --git a/debug/tst-realpath-chk.c b/debug/tst-realpath-chk.c
+new file mode 100644
+index 0000000000000000..a8fcb327c43fb34d
+--- /dev/null
++++ b/debug/tst-realpath-chk.c
+@@ -0,0 +1,37 @@
++/* Smoke test to verify that realpath does not cause spurious warnings.
++ 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
++ . */
++
++#include
++#include
++
++#include
++#include
++
++static int
++do_test (void)
++{
++#ifdef PATH_MAX
++ char buf[PATH_MAX + 1];
++ char *res = realpath (".", buf);
++ TEST_VERIFY (res == buf);
++#endif
++
++ return 0;
++}
++
++#include
+diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
+index 7ea364a276497720..81ec9bdb32215e3b 100644
+--- a/stdlib/bits/stdlib.h
++++ b/stdlib/bits/stdlib.h
+@@ -42,7 +42,7 @@ __NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
+ return __realpath_alias (__name, __resolved);
+
+ #if defined _LIBC_LIMITS_H_ && defined PATH_MAX
+- if (__glibc_unsafe_len (sz, sizeof (char), PATH_MAX))
++ if (__glibc_unsafe_len (PATH_MAX, sizeof (char), sz))
+ return __realpath_chk_warn (__name, __resolved, sz);
+ #endif
+ return __realpath_chk (__name, __resolved, sz);
diff --git a/glibc-rh2033684-11.patch b/glibc-rh2033684-11.patch
new file mode 100644
index 0000000000000000000000000000000000000000..41ce66cf5c17a37e1a61e4d2e9ae2d11a335d5d2
--- /dev/null
+++ b/glibc-rh2033684-11.patch
@@ -0,0 +1,41 @@
+commit 86bf0feb0e3ec8e37872f72499d6ae33406561d7
+Author: Siddhesh Poyarekar
+Date: Wed Jan 12 18:46:28 2022 +0530
+
+ Enable _FORTIFY_SOURCE=3 for gcc 12 and above
+
+ gcc 12 now has support for the __builtin_dynamic_object_size builtin.
+ Adapt the macro checks to enable _FORTIFY_SOURCE=3 on gcc 12 and above.
+
+ Signed-off-by: Siddhesh Poyarekar
+ Reviewed-by: Adhemerval Zanella
+
+diff --git a/include/features.h b/include/features.h
+index fe9fe16d034fad1b..2e9ca6ec2f4a0380 100644
+--- a/include/features.h
++++ b/include/features.h
+@@ -381,7 +381,9 @@
+ # warning _FORTIFY_SOURCE requires compiling with optimization (-O)
+ # elif !__GNUC_PREREQ (4, 1)
+ # warning _FORTIFY_SOURCE requires GCC 4.1 or later
+-# elif _FORTIFY_SOURCE > 2 && __glibc_clang_prereq (9, 0)
++# elif _FORTIFY_SOURCE > 2 && (__glibc_clang_prereq (9, 0) \
++ || __GNUC_PREREQ (12, 0))
++
+ # if _FORTIFY_SOURCE > 3
+ # warning _FORTIFY_SOURCE > 3 is treated like 3 on this platform
+ # endif
+diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
+index 147339957c4ad490..a17ae0ed87e6163f 100644
+--- a/misc/sys/cdefs.h
++++ b/misc/sys/cdefs.h
+@@ -124,7 +124,8 @@
+ #define __bos0(ptr) __builtin_object_size (ptr, 0)
+
+ /* Use __builtin_dynamic_object_size at _FORTIFY_SOURCE=3 when available. */
+-#if __USE_FORTIFY_LEVEL == 3 && __glibc_clang_prereq (9, 0)
++#if __USE_FORTIFY_LEVEL == 3 && (__glibc_clang_prereq (9, 0) \
++ || __GNUC_PREREQ (12, 0))
+ # define __glibc_objsize0(__o) __builtin_dynamic_object_size (__o, 0)
+ # define __glibc_objsize(__o) __builtin_dynamic_object_size (__o, 1)
+ #else
diff --git a/glibc-rh2033684-12.patch b/glibc-rh2033684-12.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9c9c98fd2cda69a04a47cd8b83f356e4dee58a99
--- /dev/null
+++ b/glibc-rh2033684-12.patch
@@ -0,0 +1,295 @@
+commit db27f1251b008280a29d540b4f8ab2a38a0d80af
+Author: Siddhesh Poyarekar
+Date: Wed Jan 12 23:34:23 2022 +0530
+
+ debug: Autogenerate _FORTIFY_SOURCE tests
+
+ Rename debug/tst-chk1.c to debug/tst-fortify.c and add make hackery to
+ autogenerate tests with different macros enabled to build and run the
+ same test with different configurations as well as different
+ fortification levels.
+
+ The change also ends up expanding the -lfs tests to include
+ _FORTIFY_SOURCE=3.
+
+ Signed-off-by: Siddhesh Poyarekar
+ Reviewed-by: Adhemerval Zanella
+
+# Conflicts:
+# debug/Makefile
+
+diff --git a/Makerules b/Makerules
+index 5d6434c74bf9bfe5..05a549eb0f259113 100644
+--- a/Makerules
++++ b/Makerules
+@@ -444,6 +444,12 @@ $(objpfx)%$o: $(objpfx)%.c $(before-compile); $$(compile-command.c)
+ endef
+ object-suffixes-left := $(all-object-suffixes)
+ include $(o-iterator)
++
++define o-iterator-doit
++$(objpfx)%$o: $(objpfx)%.cc $(before-compile); $$(compile-command.cc)
++endef
++object-suffixes-left := $(all-object-suffixes)
++include $(o-iterator)
+ endif
+
+ # Generate version maps, but wait until sysdep-subdirs is known
+diff --git a/debug/Makefile b/debug/Makefile
+index b43f42ee3851f360..c92fd23dda1a7279 100644
+--- a/debug/Makefile
++++ b/debug/Makefile
+@@ -1,4 +1,5 @@
+-# Copyright (C) 1998-2018 Free Software Foundation, Inc.
++# Copyright (C) 1998-2022 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
+@@ -110,32 +111,60 @@ CFLAGS-tst-longjmp_chk3.c += -fexceptions -fasynchronous-unwind-tables
+ CPPFLAGS-tst-longjmp_chk3.c += -D_FORTIFY_SOURCE=1
+ CPPFLAGS-tst-realpath-chk.c += -D_FORTIFY_SOURCE=2
+
++# _FORTIFY_SOURCE tests.
++# Auto-generate tests for _FORTIFY_SOURCE for different levels, compilers and
++# preprocessor conditions based on tst-fortify.c.
++#
++# To add a new test condition, define a cflags-$(cond) make variable to set
++# CFLAGS for the file.
++
++tests-all-chk = tst-fortify
++tests-c-chk =
++tests-cc-chk =
++
++CFLAGS-tst-fortify.c += -Wno-format -Wno-deprecated-declarations -Wno-error
++
++# No additional flags for the default tests.
++define cflags-default
++endef
++
++define cflags-lfs
++CFLAGS-tst-fortify-$(1)-lfs-$(2).$(1) += -D_FILE_OFFSET_BITS=64
++endef
++
+ # We know these tests have problems with format strings, this is what
+ # we are testing. Disable that warning. They are also testing
+ # deprecated functions (notably gets) so disable that warning as well.
+ # And they also generate warnings from warning attributes, which
+ # cannot be disabled via pragmas, so require -Wno-error to be used.
+-CFLAGS-tst-chk1.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-chk2.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-chk3.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-chk4.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-chk5.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-chk6.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-chk7.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-chk8.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-lfschk1.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-lfschk2.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-lfschk3.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-lfschk4.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-lfschk5.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+-CFLAGS-tst-lfschk6.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+-LDLIBS-tst-chk4 = -lstdc++
+-LDLIBS-tst-chk5 = -lstdc++
+-LDLIBS-tst-chk6 = -lstdc++
+-LDLIBS-tst-chk8 = -lstdc++
+-LDLIBS-tst-lfschk4 = -lstdc++
+-LDLIBS-tst-lfschk5 = -lstdc++
+-LDLIBS-tst-lfschk6 = -lstdc++
++define gen-chk-test
++tests-$(1)-chk += tst-fortify-$(1)-$(2)-$(3)
++CFLAGS-tst-fortify-$(1)-$(2)-$(3).$(1) += -D_FORTIFY_SOURCE=$(3) -Wno-format \
++ -Wno-deprecated-declarations \
++ -Wno-error
++$(eval $(call cflags-$(2),$(1),$(3)))
++$(objpfx)tst-fortify-$(1)-$(2)-$(3).$(1): tst-fortify.c Makefile
++ ( echo "/* Autogenerated from Makefile. */"; \
++ echo ""; \
++ echo "#include \"tst-fortify.c\"" ) > $$@.tmp
++ mv $$@.tmp $$@
++endef
++
++chk-extensions = c cc
++chk-types = default lfs
++chk-levels = 1 2 3
++
++$(foreach e,$(chk-extensions), \
++ $(foreach t,$(chk-types), \
++ $(foreach l,$(chk-levels), \
++ $(eval $(call gen-chk-test,$(e),$(t),$(l))))))
++
++tests-all-chk += $(tests-c-chk) $(tests-cc-chk)
++
++define link-cc
++LDLIBS-$(1) = -lstdc++
++endef
++$(foreach t,$(tests-cc-chk), $(eval $(call link-cc,$(t))))
+
+ # backtrace_symbols only works if we link with -rdynamic. backtrace
+ # requires unwind tables on most architectures.
+@@ -152,19 +181,25 @@ LDFLAGS-tst-backtrace6 = -rdynamic
+
+ CFLAGS-tst-ssp-1.c += -fstack-protector-all
+
+-tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \
+- tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \
+- tst-chk4 tst-chk5 tst-chk6 tst-chk7 tst-chk8 tst-lfschk4 tst-lfschk5 \
+- tst-lfschk6 tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 \
+- tst-backtrace4 tst-backtrace5 tst-backtrace6 tst-realpath-chk
++tests = backtrace-tst \
++ tst-longjmp_chk \
++ test-strcpy_chk \
++ test-stpcpy_chk \
++ tst-longjmp_chk2 \
++ tst-backtrace2 \
++ tst-backtrace3 \
++ tst-backtrace4 \
++ tst-backtrace5 \
++ tst-backtrace6 \
++ tst-realpath-chk \
++ $(tests-all-chk)
+
+ ifeq ($(have-ssp),yes)
+ tests += tst-ssp-1
+ endif
+
+ ifeq (,$(CXX))
+-tests-unsupported = tst-chk4 tst-chk5 tst-chk6 tst-chk8 \
+- tst-lfschk4 tst-lfschk5 tst-lfschk6
++tests-unsupported = $(tests-cc-chk)
+ endif
+
+ extra-libs = libSegFault libpcprofile
+@@ -191,20 +226,10 @@ ifeq ($(run-built-tests),yes)
+ LOCALES := de_DE.UTF-8
+ include ../gen-locales.mk
+
+-$(objpfx)tst-chk1.out: $(gen-locales)
+-$(objpfx)tst-chk2.out: $(gen-locales)
+-$(objpfx)tst-chk3.out: $(gen-locales)
+-$(objpfx)tst-chk4.out: $(gen-locales)
+-$(objpfx)tst-chk5.out: $(gen-locales)
+-$(objpfx)tst-chk6.out: $(gen-locales)
+-$(objpfx)tst-chk7.out: $(gen-locales)
+-$(objpfx)tst-chk8.out: $(gen-locales)
+-$(objpfx)tst-lfschk1.out: $(gen-locales)
+-$(objpfx)tst-lfschk2.out: $(gen-locales)
+-$(objpfx)tst-lfschk3.out: $(gen-locales)
+-$(objpfx)tst-lfschk4.out: $(gen-locales)
+-$(objpfx)tst-lfschk5.out: $(gen-locales)
+-$(objpfx)tst-lfschk6.out: $(gen-locales)
++define chk-gen-locales
++$(objpfx)$(1).out: $(gen-locales)
++endef
++$(foreach t, $(tests-all-chk), $(eval $(call chk-gen-locales,$(t))))
+ endif
+
+ sLIBdir := $(shell echo $(slibdir) | sed 's,lib\(\|64\)$$,\\\\$$LIB,')
+diff --git a/debug/tst-chk2.c b/debug/tst-chk2.c
+deleted file mode 100644
+index be37ce2d22f0760a..0000000000000000
+--- a/debug/tst-chk2.c
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FORTIFY_SOURCE 1
+-#include "tst-chk1.c"
+diff --git a/debug/tst-chk3.c b/debug/tst-chk3.c
+deleted file mode 100644
+index 38b8e4fb360ba722..0000000000000000
+--- a/debug/tst-chk3.c
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FORTIFY_SOURCE 2
+-#include "tst-chk1.c"
+diff --git a/debug/tst-chk4.cc b/debug/tst-chk4.cc
+deleted file mode 100644
+index c82e6aac86038791..0000000000000000
+--- a/debug/tst-chk4.cc
++++ /dev/null
+@@ -1 +0,0 @@
+-#include "tst-chk1.c"
+diff --git a/debug/tst-chk5.cc b/debug/tst-chk5.cc
+deleted file mode 100644
+index be37ce2d22f0760a..0000000000000000
+--- a/debug/tst-chk5.cc
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FORTIFY_SOURCE 1
+-#include "tst-chk1.c"
+diff --git a/debug/tst-chk6.cc b/debug/tst-chk6.cc
+deleted file mode 100644
+index 38b8e4fb360ba722..0000000000000000
+--- a/debug/tst-chk6.cc
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FORTIFY_SOURCE 2
+-#include "tst-chk1.c"
+diff --git a/debug/tst-chk7.c b/debug/tst-chk7.c
+deleted file mode 100644
+index 2a7b32381268135c..0000000000000000
+--- a/debug/tst-chk7.c
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FORTIFY_SOURCE 3
+-#include "tst-chk1.c"
+diff --git a/debug/tst-chk8.cc b/debug/tst-chk8.cc
+deleted file mode 100644
+index 2a7b32381268135c..0000000000000000
+--- a/debug/tst-chk8.cc
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FORTIFY_SOURCE 3
+-#include "tst-chk1.c"
+diff --git a/debug/tst-chk1.c b/debug/tst-fortify.c
+similarity index 100%
+rename from debug/tst-chk1.c
+rename to debug/tst-fortify.c
+diff --git a/debug/tst-lfschk1.c b/debug/tst-lfschk1.c
+deleted file mode 100644
+index f3e6d47d5e4484c3..0000000000000000
+--- a/debug/tst-lfschk1.c
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FILE_OFFSET_BITS 64
+-#include "tst-chk1.c"
+diff --git a/debug/tst-lfschk2.c b/debug/tst-lfschk2.c
+deleted file mode 100644
+index 95d4db1d32d2eeb3..0000000000000000
+--- a/debug/tst-lfschk2.c
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FILE_OFFSET_BITS 64
+-#include "tst-chk2.c"
+diff --git a/debug/tst-lfschk3.c b/debug/tst-lfschk3.c
+deleted file mode 100644
+index 50a1ae1258f1553d..0000000000000000
+--- a/debug/tst-lfschk3.c
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FILE_OFFSET_BITS 64
+-#include "tst-chk3.c"
+diff --git a/debug/tst-lfschk4.cc b/debug/tst-lfschk4.cc
+deleted file mode 100644
+index f3e6d47d5e4484c3..0000000000000000
+--- a/debug/tst-lfschk4.cc
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FILE_OFFSET_BITS 64
+-#include "tst-chk1.c"
+diff --git a/debug/tst-lfschk5.cc b/debug/tst-lfschk5.cc
+deleted file mode 100644
+index 95d4db1d32d2eeb3..0000000000000000
+--- a/debug/tst-lfschk5.cc
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FILE_OFFSET_BITS 64
+-#include "tst-chk2.c"
+diff --git a/debug/tst-lfschk6.cc b/debug/tst-lfschk6.cc
+deleted file mode 100644
+index 50a1ae1258f1553d..0000000000000000
+--- a/debug/tst-lfschk6.cc
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#define _FILE_OFFSET_BITS 64
+-#include "tst-chk3.c"
diff --git a/glibc-rh2033684-2.patch b/glibc-rh2033684-2.patch
new file mode 100644
index 0000000000000000000000000000000000000000..4651008f4d01e62fab50368ccd4534f200bbc885
--- /dev/null
+++ b/glibc-rh2033684-2.patch
@@ -0,0 +1,101 @@
+commit c43c5796121bc5bcc0867f02e5536874aa8196c1
+Author: Siddhesh Poyarekar
+Date: Wed Dec 30 11:54:00 2020 +0530
+
+ Introduce _FORTIFY_SOURCE=3
+
+ Introduce a new _FORTIFY_SOURCE level of 3 to enable additional
+ fortifications that may have a noticeable performance impact, allowing
+ more fortification coverage at the cost of some performance.
+
+ With llvm 9.0 or later, this will replace the use of
+ __builtin_object_size with __builtin_dynamic_object_size.
+
+ __builtin_dynamic_object_size
+ -----------------------------
+
+ __builtin_dynamic_object_size is an LLVM builtin that is similar to
+ __builtin_object_size. In addition to what __builtin_object_size
+ does, i.e. replace the builtin call with a constant object size,
+ __builtin_dynamic_object_size will replace the call site with an
+ expression that evaluates to the object size, thus expanding its
+ applicability. In practice, __builtin_dynamic_object_size evaluates
+ these expressions through malloc/calloc calls that it can associate
+ with the object being evaluated.
+
+ A simple motivating example is below; -D_FORTIFY_SOURCE=2 would miss
+ this and emit memcpy, but -D_FORTIFY_SOURCE=3 with the help of
+ __builtin_dynamic_object_size is able to emit __memcpy_chk with the
+ allocation size expression passed into the function:
+
+ void *copy_obj (const void *src, size_t alloc, size_t copysize)
+ {
+ void *obj = malloc (alloc);
+ memcpy (obj, src, copysize);
+ return obj;
+ }
+
+ Limitations
+ -----------
+
+ If the object was allocated elsewhere that the compiler cannot see, or
+ if it was allocated in the function with a function that the compiler
+ does not recognize as an allocator then __builtin_dynamic_object_size
+ also returns -1.
+
+ Further, the expression used to compute object size may be non-trivial
+ and may potentially incur a noticeable performance impact. These
+ fortifications are hence enabled at a new _FORTIFY_SOURCE level to
+ allow developers to make a choice on the tradeoff according to their
+ environment.
+
+diff --git a/include/features.h b/include/features.h
+index ea7673ee115bcf0a..fe9fe16d034fad1b 100644
+--- a/include/features.h
++++ b/include/features.h
+@@ -381,6 +381,11 @@
+ # warning _FORTIFY_SOURCE requires compiling with optimization (-O)
+ # elif !__GNUC_PREREQ (4, 1)
+ # warning _FORTIFY_SOURCE requires GCC 4.1 or later
++# elif _FORTIFY_SOURCE > 2 && __glibc_clang_prereq (9, 0)
++# if _FORTIFY_SOURCE > 3
++# warning _FORTIFY_SOURCE > 3 is treated like 3 on this platform
++# endif
++# define __USE_FORTIFY_LEVEL 3
+ # elif _FORTIFY_SOURCE > 1
+ # if _FORTIFY_SOURCE > 2
+ # warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform
+diff --git a/manual/creature.texi b/manual/creature.texi
+index 8876b2ab779c988f..64f361f27a7d6cdf 100644
+--- a/manual/creature.texi
++++ b/manual/creature.texi
+@@ -247,7 +247,8 @@ included.
+ @standards{GNU, (none)}
+ If this macro is defined to @math{1}, security hardening is added to
+ various library functions. If defined to @math{2}, even stricter
+-checks are applied.
++checks are applied. If defined to @math{3}, @theglibc{} may also use
++checks that may have an additional performance overhead.
+ @end defvr
+
+ @defvr Macro _REENTRANT
+diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
+index 3f6fe3cc8563b493..1e39307b0ebcf38f 100644
+--- a/misc/sys/cdefs.h
++++ b/misc/sys/cdefs.h
+@@ -123,6 +123,15 @@
+ #define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)
+ #define __bos0(ptr) __builtin_object_size (ptr, 0)
+
++/* Use __builtin_dynamic_object_size at _FORTIFY_SOURCE=3 when available. */
++#if __USE_FORTIFY_LEVEL == 3 && __glibc_clang_prereq (9, 0)
++# define __glibc_objsize0(__o) __builtin_dynamic_object_size (__o, 0)
++# define __glibc_objsize(__o) __builtin_dynamic_object_size (__o, 1)
++#else
++# define __glibc_objsize0(__o) __bos0 (__o)
++# define __glibc_objsize(__o) __bos (__o)
++#endif
++
+ #if __GNUC_PREREQ (4,3)
+ # define __warndecl(name, msg) \
+ extern void name (void) __attribute__((__warning__ (msg)))
diff --git a/glibc-rh2033684-3.patch b/glibc-rh2033684-3.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b8d009356cf758326a49dcddd05377aa000b4923
--- /dev/null
+++ b/glibc-rh2033684-3.patch
@@ -0,0 +1,43 @@
+commit 7163ace3318d666d40771f5c8e7c4a148827070f
+Author: Siddhesh Poyarekar
+Date: Thu Nov 12 12:09:56 2020 +0530
+
+ Use __builtin___stpncpy_chk when available
+
+ The builtin has been available in gcc since 4.7.0 and in clang since
+ 2.6. This fixes stpncpy fortification with clang since it does a
+ better job of plugging in __stpncpy_chk in the right place than the
+ header hackery.
+
+ This has been tested by building and running all tests with gcc 10.2.1
+ and also with clang tip as of a few days ago (just the tests in debug/
+ since running all tests don't work with clang at the moment) to make
+ sure that both compilers pass the stpncpy tests.
+
+diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h
+index a07ab0dbc8c8dd5b..4ed6755a6c1ca247 100644
+--- a/string/bits/string_fortified.h
++++ b/string/bits/string_fortified.h
+@@ -106,7 +106,13 @@ __NTH (strncpy (char *__restrict __dest, const char *__restrict __src,
+ return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
+ }
+
+-/* XXX We have no corresponding builtin yet. */
++#if __GNUC_PREREQ (4, 7) || __glibc_clang_prereq (2, 6)
++__fortify_function char *
++__NTH (stpncpy (char *__dest, const char *__src, size_t __n))
++{
++ return __builtin___stpncpy_chk (__dest, __src, __n, __bos (__dest));
++}
++#else
+ extern char *__stpncpy_chk (char *__dest, const char *__src, size_t __n,
+ size_t __destlen) __THROW;
+ extern char *__REDIRECT_NTH (__stpncpy_alias, (char *__dest, const char *__src,
+@@ -120,6 +126,7 @@ __NTH (stpncpy (char *__dest, const char *__src, size_t __n))
+ return __stpncpy_chk (__dest, __src, __n, __bos (__dest));
+ return __stpncpy_alias (__dest, __src, __n);
+ }
++#endif
+
+
+ __fortify_function char *
diff --git a/glibc-rh2033684-4.patch b/glibc-rh2033684-4.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ebd0c338a25f3713823c8314b7dceb97683d4657
--- /dev/null
+++ b/glibc-rh2033684-4.patch
@@ -0,0 +1,161 @@
+commit 2a3224c53653214cbba2ec23424702193c80ea3b
+Author: Siddhesh Poyarekar
+Date: Wed Dec 30 11:09:58 2020 +0530
+
+ string: Enable __FORTIFY_LEVEL=3
+
+ This change enhances fortified string functions to use
+ __builtin_dynamic_object_size under _FORTIFY_SOURCE=3 whenever the
+ compiler supports it.
+
+# Conflicts:
+# string/bits/string_fortified.h
+
+Conflict resolved to retain __GNUC_PREREQ (5,0) macro check in RHEL-8
+glibc.
+
+diff --git a/include/string.h b/include/string.h
+index 4d622f1c0305e78e..bbc97082661caf42 100644
+--- a/include/string.h
++++ b/include/string.h
+@@ -119,10 +119,11 @@ libc_hidden_proto (__ffs)
+ void __explicit_bzero_chk_internal (void *, size_t, size_t)
+ __THROW __nonnull ((1)) attribute_hidden;
+ # define explicit_bzero(buf, len) \
+- __explicit_bzero_chk_internal (buf, len, __bos0 (buf))
++ __explicit_bzero_chk_internal (buf, len, __glibc_objsize0 (buf))
+ #elif !IS_IN (nonlib)
+ void __explicit_bzero_chk (void *, size_t, size_t) __THROW __nonnull ((1));
+-# define explicit_bzero(buf, len) __explicit_bzero_chk (buf, len, __bos0 (buf))
++# define explicit_bzero(buf, len) __explicit_bzero_chk (buf, len, \
++ __glibc_objsize0 (buf))
+ #endif
+
+ libc_hidden_builtin_proto (memchr)
+diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h
+index 4ed6755a6c1ca247..27ec273ec41cd81c 100644
+--- a/string/bits/string_fortified.h
++++ b/string/bits/string_fortified.h
+@@ -31,13 +31,15 @@ __fortify_function void *
+ __NTH (memcpy (void *__restrict __dest, const void *__restrict __src,
+ size_t __len))
+ {
+- return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
++ return __builtin___memcpy_chk (__dest, __src, __len,
++ __glibc_objsize0 (__dest));
+ }
+
+ __fortify_function void *
+ __NTH (memmove (void *__dest, const void *__src, size_t __len))
+ {
+- return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
++ return __builtin___memmove_chk (__dest, __src, __len,
++ __glibc_objsize0 (__dest));
+ }
+
+ #ifdef __USE_GNU
+@@ -45,7 +47,8 @@ __fortify_function void *
+ __NTH (mempcpy (void *__restrict __dest, const void *__restrict __src,
+ size_t __len))
+ {
+- return __builtin___mempcpy_chk (__dest, __src, __len, __bos0 (__dest));
++ return __builtin___mempcpy_chk (__dest, __src, __len,
++ __glibc_objsize0 (__dest));
+ }
+ #endif
+
+@@ -68,7 +71,8 @@ __NTH (memset (void *__dest, int __ch, size_t __len))
+ return __dest;
+ }
+ #endif
+- return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest));
++ return __builtin___memset_chk (__dest, __ch, __len,
++ __glibc_objsize0 (__dest));
+ }
+
+ #ifdef __USE_MISC
+@@ -80,21 +84,21 @@ void __explicit_bzero_chk (void *__dest, size_t __len, size_t __destlen)
+ __fortify_function void
+ __NTH (explicit_bzero (void *__dest, size_t __len))
+ {
+- __explicit_bzero_chk (__dest, __len, __bos0 (__dest));
++ __explicit_bzero_chk (__dest, __len, __glibc_objsize0 (__dest));
+ }
+ #endif
+
+ __fortify_function char *
+ __NTH (strcpy (char *__restrict __dest, const char *__restrict __src))
+ {
+- return __builtin___strcpy_chk (__dest, __src, __bos (__dest));
++ return __builtin___strcpy_chk (__dest, __src, __glibc_objsize (__dest));
+ }
+
+ #ifdef __USE_GNU
+ __fortify_function char *
+ __NTH (stpcpy (char *__restrict __dest, const char *__restrict __src))
+ {
+- return __builtin___stpcpy_chk (__dest, __src, __bos (__dest));
++ return __builtin___stpcpy_chk (__dest, __src, __glibc_objsize (__dest));
+ }
+ #endif
+
+@@ -103,14 +107,16 @@ __fortify_function char *
+ __NTH (strncpy (char *__restrict __dest, const char *__restrict __src,
+ size_t __len))
+ {
+- return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
++ return __builtin___strncpy_chk (__dest, __src, __len,
++ __glibc_objsize (__dest));
+ }
+
+ #if __GNUC_PREREQ (4, 7) || __glibc_clang_prereq (2, 6)
+ __fortify_function char *
+ __NTH (stpncpy (char *__dest, const char *__src, size_t __n))
+ {
+- return __builtin___stpncpy_chk (__dest, __src, __n, __bos (__dest));
++ return __builtin___stpncpy_chk (__dest, __src, __n,
++ __glibc_objsize (__dest));
+ }
+ #else
+ extern char *__stpncpy_chk (char *__dest, const char *__src, size_t __n,
+@@ -132,7 +138,7 @@ __NTH (stpncpy (char *__dest, const char *__src, size_t __n))
+ __fortify_function char *
+ __NTH (strcat (char *__restrict __dest, const char *__restrict __src))
+ {
+- return __builtin___strcat_chk (__dest, __src, __bos (__dest));
++ return __builtin___strcat_chk (__dest, __src, __glibc_objsize (__dest));
+ }
+
+
+@@ -140,7 +146,8 @@ __fortify_function char *
+ __NTH (strncat (char *__restrict __dest, const char *__restrict __src,
+ size_t __len))
+ {
+- return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));
++ return __builtin___strncat_chk (__dest, __src, __len,
++ __glibc_objsize (__dest));
+ }
+
+ #endif /* bits/string_fortified.h */
+diff --git a/string/bits/strings_fortified.h b/string/bits/strings_fortified.h
+index d9b2804525cfa994..871515bd2cba1f8a 100644
+--- a/string/bits/strings_fortified.h
++++ b/string/bits/strings_fortified.h
+@@ -22,13 +22,15 @@
+ __fortify_function void
+ __NTH (bcopy (const void *__src, void *__dest, size_t __len))
+ {
+- (void) __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
++ (void) __builtin___memmove_chk (__dest, __src, __len,
++ __glibc_objsize0 (__dest));
+ }
+
+ __fortify_function void
+ __NTH (bzero (void *__dest, size_t __len))
+ {
+- (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
++ (void) __builtin___memset_chk (__dest, '\0', __len,
++ __glibc_objsize0 (__dest));
+ }
+
+ #endif
diff --git a/glibc-rh2033684-5.patch b/glibc-rh2033684-5.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8c1f7f30c1e8ae328ae95014037f0bb76914aa36
--- /dev/null
+++ b/glibc-rh2033684-5.patch
@@ -0,0 +1,963 @@
+commit f9de8bfe1a731c309b91d175b4f6f4aeb786effa
+Author: Siddhesh Poyarekar
+Date: Tue Dec 15 23:50:09 2020 +0530
+
+ nonstring: Enable __FORTIFY_LEVEL=3
+
+ Use __builtin_dynamic_object_size in the remaining functions that
+ don't have compiler builtins as is the case for string functions.
+
+diff --git a/io/bits/poll2.h b/io/bits/poll2.h
+index 7e8406b87d6319f8..f47fd9ad0945234f 100644
+--- a/io/bits/poll2.h
++++ b/io/bits/poll2.h
+@@ -35,12 +35,13 @@ extern int __REDIRECT (__poll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
+ __fortify_function int
+ poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+ {
+- if (__bos (__fds) != (__SIZE_TYPE__) -1)
++ if (__glibc_objsize (__fds) != (__SIZE_TYPE__) -1)
+ {
+ if (! __builtin_constant_p (__nfds))
+- return __poll_chk (__fds, __nfds, __timeout, __bos (__fds));
+- else if (__bos (__fds) / sizeof (*__fds) < __nfds)
+- return __poll_chk_warn (__fds, __nfds, __timeout, __bos (__fds));
++ return __poll_chk (__fds, __nfds, __timeout, __glibc_objsize (__fds));
++ else if (__glibc_objsize (__fds) / sizeof (*__fds) < __nfds)
++ return __poll_chk_warn (__fds, __nfds, __timeout,
++ __glibc_objsize (__fds));
+ }
+
+ return __poll_alias (__fds, __nfds, __timeout);
+@@ -65,13 +66,14 @@ __fortify_function int
+ ppoll (struct pollfd *__fds, nfds_t __nfds, const struct timespec *__timeout,
+ const __sigset_t *__ss)
+ {
+- if (__bos (__fds) != (__SIZE_TYPE__) -1)
++ if (__glibc_objsize (__fds) != (__SIZE_TYPE__) -1)
+ {
+ if (! __builtin_constant_p (__nfds))
+- return __ppoll_chk (__fds, __nfds, __timeout, __ss, __bos (__fds));
+- else if (__bos (__fds) / sizeof (*__fds) < __nfds)
++ return __ppoll_chk (__fds, __nfds, __timeout, __ss,
++ __glibc_objsize (__fds));
++ else if (__glibc_objsize (__fds) / sizeof (*__fds) < __nfds)
+ return __ppoll_chk_warn (__fds, __nfds, __timeout, __ss,
+- __bos (__fds));
++ __glibc_objsize (__fds));
+ }
+
+ return __ppoll_alias (__fds, __nfds, __timeout, __ss);
+diff --git a/libio/bits/stdio.h b/libio/bits/stdio.h
+index 4ab919031f77a960..1372d4bf70c43d53 100644
+--- a/libio/bits/stdio.h
++++ b/libio/bits/stdio.h
+@@ -31,7 +31,7 @@
+
+
+ #ifdef __USE_EXTERN_INLINES
+-/* For -D_FORTIFY_SOURCE{,=2} bits/stdio2.h will define a different
++/* For -D_FORTIFY_SOURCE{,=2,=3} bits/stdio2.h will define a different
+ inline. */
+ # if !(__USE_FORTIFY_LEVEL > 0 && defined __fortify_function)
+ /* Write formatted output to stdout from argument list ARG. */
+diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
+index 11651506a67daea0..2cd69f44cfadfc9f 100644
+--- a/libio/bits/stdio2.h
++++ b/libio/bits/stdio2.h
+@@ -34,12 +34,13 @@ __fortify_function int
+ __NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...))
+ {
+ return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
+- __bos (__s), __fmt, __va_arg_pack ());
++ __glibc_objsize (__s), __fmt,
++ __va_arg_pack ());
+ }
+ #elif !defined __cplusplus
+ # define sprintf(str, ...) \
+- __builtin___sprintf_chk (str, __USE_FORTIFY_LEVEL - 1, __bos (str), \
+- __VA_ARGS__)
++ __builtin___sprintf_chk (str, __USE_FORTIFY_LEVEL - 1, \
++ __glibc_objsize (str), __VA_ARGS__)
+ #endif
+
+ __fortify_function int
+@@ -47,7 +48,7 @@ __NTH (vsprintf (char *__restrict __s, const char *__restrict __fmt,
+ __gnuc_va_list __ap))
+ {
+ return __builtin___vsprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
+- __bos (__s), __fmt, __ap);
++ __glibc_objsize (__s), __fmt, __ap);
+ }
+
+ #if defined __USE_ISOC99 || defined __USE_UNIX98
+@@ -65,12 +66,13 @@ __NTH (snprintf (char *__restrict __s, size_t __n,
+ const char *__restrict __fmt, ...))
+ {
+ return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
+- __bos (__s), __fmt, __va_arg_pack ());
++ __glibc_objsize (__s), __fmt,
++ __va_arg_pack ());
+ }
+ # elif !defined __cplusplus
+ # define snprintf(str, len, ...) \
+- __builtin___snprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1, __bos (str), \
+- __VA_ARGS__)
++ __builtin___snprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1, \
++ __glibc_objsize (str), __VA_ARGS__)
+ # endif
+
+ __fortify_function int
+@@ -78,7 +80,7 @@ __NTH (vsnprintf (char *__restrict __s, size_t __n,
+ const char *__restrict __fmt, __gnuc_va_list __ap))
+ {
+ return __builtin___vsnprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
+- __bos (__s), __fmt, __ap);
++ __glibc_objsize (__s), __fmt, __ap);
+ }
+
+ #endif
+@@ -234,8 +236,8 @@ extern char *__REDIRECT (__gets_warn, (char *__str), gets)
+ __fortify_function __wur char *
+ gets (char *__str)
+ {
+- if (__bos (__str) != (size_t) -1)
+- return __gets_chk (__str, __bos (__str));
++ if (__glibc_objsize (__str) != (size_t) -1)
++ return __gets_chk (__str, __glibc_objsize (__str));
+ return __gets_warn (__str);
+ }
+ #endif
+@@ -254,13 +256,13 @@ extern char *__REDIRECT (__fgets_chk_warn,
+ __fortify_function __wur char *
+ fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
+ {
+- if (__bos (__s) != (size_t) -1)
++ if (__glibc_objsize (__s) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n) || __n <= 0)
+- return __fgets_chk (__s, __bos (__s), __n, __stream);
++ return __fgets_chk (__s, __glibc_objsize (__s), __n, __stream);
+
+- if ((size_t) __n > __bos (__s))
+- return __fgets_chk_warn (__s, __bos (__s), __n, __stream);
++ if ((size_t) __n > __glibc_objsize (__s))
++ return __fgets_chk_warn (__s, __glibc_objsize (__s), __n, __stream);
+ }
+ return __fgets_alias (__s, __n, __stream);
+ }
+@@ -284,15 +286,17 @@ __fortify_function __wur size_t
+ fread (void *__restrict __ptr, size_t __size, size_t __n,
+ FILE *__restrict __stream)
+ {
+- if (__bos0 (__ptr) != (size_t) -1)
++ if (__glibc_objsize0 (__ptr) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__size)
+ || !__builtin_constant_p (__n)
+ || (__size | __n) >= (((size_t) 1) << (8 * sizeof (size_t) / 2)))
+- return __fread_chk (__ptr, __bos0 (__ptr), __size, __n, __stream);
++ return __fread_chk (__ptr, __glibc_objsize0 (__ptr), __size, __n,
++ __stream);
+
+- if (__size * __n > __bos0 (__ptr))
+- return __fread_chk_warn (__ptr, __bos0 (__ptr), __size, __n, __stream);
++ if (__size * __n > __glibc_objsize0 (__ptr))
++ return __fread_chk_warn (__ptr, __glibc_objsize0 (__ptr), __size, __n,
++ __stream);
+ }
+ return __fread_alias (__ptr, __size, __n, __stream);
+ }
+@@ -312,13 +316,15 @@ extern char *__REDIRECT (__fgets_unlocked_chk_warn,
+ __fortify_function __wur char *
+ fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream)
+ {
+- if (__bos (__s) != (size_t) -1)
++ if (__glibc_objsize (__s) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n) || __n <= 0)
+- return __fgets_unlocked_chk (__s, __bos (__s), __n, __stream);
++ return __fgets_unlocked_chk (__s, __glibc_objsize (__s), __n,
++ __stream);
+
+- if ((size_t) __n > __bos (__s))
+- return __fgets_unlocked_chk_warn (__s, __bos (__s), __n, __stream);
++ if ((size_t) __n > __glibc_objsize (__s))
++ return __fgets_unlocked_chk_warn (__s, __glibc_objsize (__s), __n,
++ __stream);
+ }
+ return __fgets_unlocked_alias (__s, __n, __stream);
+ }
+@@ -345,17 +351,17 @@ __fortify_function __wur size_t
+ fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
+ FILE *__restrict __stream)
+ {
+- if (__bos0 (__ptr) != (size_t) -1)
++ if (__glibc_objsize0 (__ptr) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__size)
+ || !__builtin_constant_p (__n)
+ || (__size | __n) >= (((size_t) 1) << (8 * sizeof (size_t) / 2)))
+- return __fread_unlocked_chk (__ptr, __bos0 (__ptr), __size, __n,
+- __stream);
++ return __fread_unlocked_chk (__ptr, __glibc_objsize0 (__ptr), __size,
++ __n, __stream);
+
+- if (__size * __n > __bos0 (__ptr))
+- return __fread_unlocked_chk_warn (__ptr, __bos0 (__ptr), __size, __n,
+- __stream);
++ if (__size * __n > __glibc_objsize0 (__ptr))
++ return __fread_unlocked_chk_warn (__ptr, __glibc_objsize0 (__ptr),
++ __size, __n, __stream);
+ }
+
+ # ifdef __USE_EXTERN_INLINES
+diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h
+index 9a749dccf8de65cd..a0c4dcfe9c61a7b8 100644
+--- a/posix/bits/unistd.h
++++ b/posix/bits/unistd.h
+@@ -33,13 +33,14 @@ extern ssize_t __REDIRECT (__read_chk_warn,
+ __fortify_function __wur ssize_t
+ read (int __fd, void *__buf, size_t __nbytes)
+ {
+- if (__bos0 (__buf) != (size_t) -1)
++ if (__glibc_objsize0 (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__nbytes))
+- return __read_chk (__fd, __buf, __nbytes, __bos0 (__buf));
++ return __read_chk (__fd, __buf, __nbytes, __glibc_objsize0 (__buf));
+
+- if (__nbytes > __bos0 (__buf))
+- return __read_chk_warn (__fd, __buf, __nbytes, __bos0 (__buf));
++ if (__nbytes > __glibc_objsize0 (__buf))
++ return __read_chk_warn (__fd, __buf, __nbytes,
++ __glibc_objsize0 (__buf));
+ }
+ return __read_alias (__fd, __buf, __nbytes);
+ }
+@@ -71,14 +72,15 @@ extern ssize_t __REDIRECT (__pread64_chk_warn,
+ __fortify_function __wur ssize_t
+ pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset)
+ {
+- if (__bos0 (__buf) != (size_t) -1)
++ if (__glibc_objsize0 (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__nbytes))
+- return __pread_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
++ return __pread_chk (__fd, __buf, __nbytes, __offset,
++ __glibc_objsize0 (__buf));
+
+- if ( __nbytes > __bos0 (__buf))
++ if ( __nbytes > __glibc_objsize0 (__buf))
+ return __pread_chk_warn (__fd, __buf, __nbytes, __offset,
+- __bos0 (__buf));
++ __glibc_objsize0 (__buf));
+ }
+ return __pread_alias (__fd, __buf, __nbytes, __offset);
+ }
+@@ -86,14 +88,15 @@ pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset)
+ __fortify_function __wur ssize_t
+ pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+ {
+- if (__bos0 (__buf) != (size_t) -1)
++ if (__glibc_objsize0 (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__nbytes))
+- return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
++ return __pread64_chk (__fd, __buf, __nbytes, __offset,
++ __glibc_objsize0 (__buf));
+
+- if ( __nbytes > __bos0 (__buf))
++ if ( __nbytes > __glibc_objsize0 (__buf))
+ return __pread64_chk_warn (__fd, __buf, __nbytes, __offset,
+- __bos0 (__buf));
++ __glibc_objsize0 (__buf));
+ }
+
+ return __pread64_alias (__fd, __buf, __nbytes, __offset);
+@@ -104,14 +107,15 @@ pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+ __fortify_function __wur ssize_t
+ pread64 (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+ {
+- if (__bos0 (__buf) != (size_t) -1)
++ if (__glibc_objsize0 (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__nbytes))
+- return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
++ return __pread64_chk (__fd, __buf, __nbytes, __offset,
++ __glibc_objsize0 (__buf));
+
+- if ( __nbytes > __bos0 (__buf))
++ if ( __nbytes > __glibc_objsize0 (__buf))
+ return __pread64_chk_warn (__fd, __buf, __nbytes, __offset,
+- __bos0 (__buf));
++ __glibc_objsize0 (__buf));
+ }
+
+ return __pread64_alias (__fd, __buf, __nbytes, __offset);
+@@ -139,13 +143,14 @@ __fortify_function __nonnull ((1, 2)) __wur ssize_t
+ __NTH (readlink (const char *__restrict __path, char *__restrict __buf,
+ size_t __len))
+ {
+- if (__bos (__buf) != (size_t) -1)
++ if (__glibc_objsize (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__len))
+- return __readlink_chk (__path, __buf, __len, __bos (__buf));
++ return __readlink_chk (__path, __buf, __len, __glibc_objsize (__buf));
+
+- if ( __len > __bos (__buf))
+- return __readlink_chk_warn (__path, __buf, __len, __bos (__buf));
++ if ( __len > __glibc_objsize (__buf))
++ return __readlink_chk_warn (__path, __buf, __len,
++ __glibc_objsize (__buf));
+ }
+ return __readlink_alias (__path, __buf, __len);
+ }
+@@ -173,14 +178,15 @@ __fortify_function __nonnull ((2, 3)) __wur ssize_t
+ __NTH (readlinkat (int __fd, const char *__restrict __path,
+ char *__restrict __buf, size_t __len))
+ {
+- if (__bos (__buf) != (size_t) -1)
++ if (__glibc_objsize (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__len))
+- return __readlinkat_chk (__fd, __path, __buf, __len, __bos (__buf));
++ return __readlinkat_chk (__fd, __path, __buf, __len,
++ __glibc_objsize (__buf));
+
+- if (__len > __bos (__buf))
++ if (__len > __glibc_objsize (__buf))
+ return __readlinkat_chk_warn (__fd, __path, __buf, __len,
+- __bos (__buf));
++ __glibc_objsize (__buf));
+ }
+ return __readlinkat_alias (__fd, __path, __buf, __len);
+ }
+@@ -199,13 +205,13 @@ extern char *__REDIRECT_NTH (__getcwd_chk_warn,
+ __fortify_function __wur char *
+ __NTH (getcwd (char *__buf, size_t __size))
+ {
+- if (__bos (__buf) != (size_t) -1)
++ if (__glibc_objsize (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__size))
+- return __getcwd_chk (__buf, __size, __bos (__buf));
++ return __getcwd_chk (__buf, __size, __glibc_objsize (__buf));
+
+- if (__size > __bos (__buf))
+- return __getcwd_chk_warn (__buf, __size, __bos (__buf));
++ if (__size > __glibc_objsize (__buf))
++ return __getcwd_chk_warn (__buf, __size, __glibc_objsize (__buf));
+ }
+ return __getcwd_alias (__buf, __size);
+ }
+@@ -220,8 +226,8 @@ extern char *__REDIRECT_NTH (__getwd_warn, (char *__buf), getwd)
+ __fortify_function __nonnull ((1)) __attribute_deprecated__ __wur char *
+ __NTH (getwd (char *__buf))
+ {
+- if (__bos (__buf) != (size_t) -1)
+- return __getwd_chk (__buf, __bos (__buf));
++ if (__glibc_objsize (__buf) != (size_t) -1)
++ return __getwd_chk (__buf, __glibc_objsize (__buf));
+ return __getwd_warn (__buf);
+ }
+ #endif
+@@ -239,13 +245,14 @@ extern size_t __REDIRECT_NTH (__confstr_chk_warn,
+ __fortify_function size_t
+ __NTH (confstr (int __name, char *__buf, size_t __len))
+ {
+- if (__bos (__buf) != (size_t) -1)
++ if (__glibc_objsize (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__len))
+- return __confstr_chk (__name, __buf, __len, __bos (__buf));
++ return __confstr_chk (__name, __buf, __len, __glibc_objsize (__buf));
+
+- if (__bos (__buf) < __len)
+- return __confstr_chk_warn (__name, __buf, __len, __bos (__buf));
++ if (__glibc_objsize (__buf) < __len)
++ return __confstr_chk_warn (__name, __buf, __len,
++ __glibc_objsize (__buf));
+ }
+ return __confstr_alias (__name, __buf, __len);
+ }
+@@ -264,13 +271,13 @@ extern int __REDIRECT_NTH (__getgroups_chk_warn,
+ __fortify_function int
+ __NTH (getgroups (int __size, __gid_t __list[]))
+ {
+- if (__bos (__list) != (size_t) -1)
++ if (__glibc_objsize (__list) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__size) || __size < 0)
+- return __getgroups_chk (__size, __list, __bos (__list));
++ return __getgroups_chk (__size, __list, __glibc_objsize (__list));
+
+- if (__size * sizeof (__gid_t) > __bos (__list))
+- return __getgroups_chk_warn (__size, __list, __bos (__list));
++ if (__size * sizeof (__gid_t) > __glibc_objsize (__list))
++ return __getgroups_chk_warn (__size, __list, __glibc_objsize (__list));
+ }
+ return __getgroups_alias (__size, __list);
+ }
+@@ -290,13 +297,15 @@ extern int __REDIRECT_NTH (__ttyname_r_chk_warn,
+ __fortify_function int
+ __NTH (ttyname_r (int __fd, char *__buf, size_t __buflen))
+ {
+- if (__bos (__buf) != (size_t) -1)
++ if (__glibc_objsize (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__buflen))
+- return __ttyname_r_chk (__fd, __buf, __buflen, __bos (__buf));
++ return __ttyname_r_chk (__fd, __buf, __buflen,
++ __glibc_objsize (__buf));
+
+- if (__buflen > __bos (__buf))
+- return __ttyname_r_chk_warn (__fd, __buf, __buflen, __bos (__buf));
++ if (__buflen > __glibc_objsize (__buf))
++ return __ttyname_r_chk_warn (__fd, __buf, __buflen,
++ __glibc_objsize (__buf));
+ }
+ return __ttyname_r_alias (__fd, __buf, __buflen);
+ }
+@@ -316,13 +325,14 @@ extern int __REDIRECT (__getlogin_r_chk_warn,
+ __fortify_function int
+ getlogin_r (char *__buf, size_t __buflen)
+ {
+- if (__bos (__buf) != (size_t) -1)
++ if (__glibc_objsize (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__buflen))
+- return __getlogin_r_chk (__buf, __buflen, __bos (__buf));
++ return __getlogin_r_chk (__buf, __buflen, __glibc_objsize (__buf));
+
+- if (__buflen > __bos (__buf))
+- return __getlogin_r_chk_warn (__buf, __buflen, __bos (__buf));
++ if (__buflen > __glibc_objsize (__buf))
++ return __getlogin_r_chk_warn (__buf, __buflen,
++ __glibc_objsize (__buf));
+ }
+ return __getlogin_r_alias (__buf, __buflen);
+ }
+@@ -343,13 +353,14 @@ extern int __REDIRECT_NTH (__gethostname_chk_warn,
+ __fortify_function int
+ __NTH (gethostname (char *__buf, size_t __buflen))
+ {
+- if (__bos (__buf) != (size_t) -1)
++ if (__glibc_objsize (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__buflen))
+- return __gethostname_chk (__buf, __buflen, __bos (__buf));
++ return __gethostname_chk (__buf, __buflen, __glibc_objsize (__buf));
+
+- if (__buflen > __bos (__buf))
+- return __gethostname_chk_warn (__buf, __buflen, __bos (__buf));
++ if (__buflen > __glibc_objsize (__buf))
++ return __gethostname_chk_warn (__buf, __buflen,
++ __glibc_objsize (__buf));
+ }
+ return __gethostname_alias (__buf, __buflen);
+ }
+@@ -372,13 +383,14 @@ extern int __REDIRECT_NTH (__getdomainname_chk_warn,
+ __fortify_function int
+ __NTH (getdomainname (char *__buf, size_t __buflen))
+ {
+- if (__bos (__buf) != (size_t) -1)
++ if (__glibc_objsize (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__buflen))
+- return __getdomainname_chk (__buf, __buflen, __bos (__buf));
++ return __getdomainname_chk (__buf, __buflen, __glibc_objsize (__buf));
+
+- if (__buflen > __bos (__buf))
+- return __getdomainname_chk_warn (__buf, __buflen, __bos (__buf));
++ if (__buflen > __glibc_objsize (__buf))
++ return __getdomainname_chk_warn (__buf, __buflen,
++ __glibc_objsize (__buf));
+ }
+ return __getdomainname_alias (__buf, __buflen);
+ }
+diff --git a/socket/bits/socket2.h b/socket/bits/socket2.h
+index a129e697352fd7cb..729e5a4cc1f4cb92 100644
+--- a/socket/bits/socket2.h
++++ b/socket/bits/socket2.h
+@@ -33,13 +33,15 @@ extern ssize_t __REDIRECT (__recv_chk_warn,
+ __fortify_function ssize_t
+ recv (int __fd, void *__buf, size_t __n, int __flags)
+ {
+- if (__bos0 (__buf) != (size_t) -1)
++ if (__glibc_objsize0 (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n))
+- return __recv_chk (__fd, __buf, __n, __bos0 (__buf), __flags);
++ return __recv_chk (__fd, __buf, __n, __glibc_objsize0 (__buf),
++ __flags);
+
+- if (__n > __bos0 (__buf))
+- return __recv_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags);
++ if (__n > __glibc_objsize0 (__buf))
++ return __recv_chk_warn (__fd, __buf, __n, __glibc_objsize0 (__buf),
++ __flags);
+ }
+ return __recv_alias (__fd, __buf, __n, __flags);
+ }
+@@ -64,14 +66,14 @@ __fortify_function ssize_t
+ recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags,
+ __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)
+ {
+- if (__bos0 (__buf) != (size_t) -1)
++ if (__glibc_objsize0 (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n))
+- return __recvfrom_chk (__fd, __buf, __n, __bos0 (__buf), __flags,
+- __addr, __addr_len);
+- if (__n > __bos0 (__buf))
+- return __recvfrom_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags,
+- __addr, __addr_len);
++ return __recvfrom_chk (__fd, __buf, __n, __glibc_objsize0 (__buf),
++ __flags, __addr, __addr_len);
++ if (__n > __glibc_objsize0 (__buf))
++ return __recvfrom_chk_warn (__fd, __buf, __n, __glibc_objsize0 (__buf),
++ __flags, __addr, __addr_len);
+ }
+ return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len);
+ }
+diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
+index 53c379b99ae9d5fe..5e4114ded33f2033 100644
+--- a/stdlib/bits/stdlib.h
++++ b/stdlib/bits/stdlib.h
+@@ -36,13 +36,14 @@ extern char *__REDIRECT_NTH (__realpath_chk_warn,
+ __fortify_function __wur char *
+ __NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
+ {
+- if (__bos (__resolved) != (size_t) -1)
++ if (__glibc_objsize (__resolved) != (size_t) -1)
+ {
+ #if defined _LIBC_LIMITS_H_ && defined PATH_MAX
+- if (__bos (__resolved) < PATH_MAX)
+- return __realpath_chk_warn (__name, __resolved, __bos (__resolved));
++ if (__glibc_objsize (__resolved) < PATH_MAX)
++ return __realpath_chk_warn (__name, __resolved,
++ __glibc_objsize (__resolved));
+ #endif
+- return __realpath_chk (__name, __resolved, __bos (__resolved));
++ return __realpath_chk (__name, __resolved, __glibc_objsize (__resolved));
+ }
+
+ return __realpath_alias (__name, __resolved);
+@@ -63,12 +64,14 @@ extern int __REDIRECT_NTH (__ptsname_r_chk_warn,
+ __fortify_function int
+ __NTH (ptsname_r (int __fd, char *__buf, size_t __buflen))
+ {
+- if (__bos (__buf) != (size_t) -1)
++ if (__glibc_objsize (__buf) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__buflen))
+- return __ptsname_r_chk (__fd, __buf, __buflen, __bos (__buf));
+- if (__buflen > __bos (__buf))
+- return __ptsname_r_chk_warn (__fd, __buf, __buflen, __bos (__buf));
++ return __ptsname_r_chk (__fd, __buf, __buflen,
++ __glibc_objsize (__buf));
++ if (__buflen > __glibc_objsize (__buf))
++ return __ptsname_r_chk_warn (__fd, __buf, __buflen,
++ __glibc_objsize (__buf));
+ }
+ return __ptsname_r_alias (__fd, __buf, __buflen);
+ }
+@@ -89,8 +92,9 @@ __NTH (wctomb (char *__s, wchar_t __wchar))
+ #if defined MB_LEN_MAX && MB_LEN_MAX != __STDLIB_MB_LEN_MAX
+ # error "Assumed value of MB_LEN_MAX wrong"
+ #endif
+- if (__bos (__s) != (size_t) -1 && __STDLIB_MB_LEN_MAX > __bos (__s))
+- return __wctomb_chk (__s, __wchar, __bos (__s));
++ if (__glibc_objsize (__s) != (size_t) -1
++ && __STDLIB_MB_LEN_MAX > __glibc_objsize (__s))
++ return __wctomb_chk (__s, __wchar, __glibc_objsize (__s));
+ return __wctomb_alias (__s, __wchar);
+ }
+
+@@ -113,15 +117,16 @@ __fortify_function size_t
+ __NTH (mbstowcs (wchar_t *__restrict __dst, const char *__restrict __src,
+ size_t __len))
+ {
+- if (__bos (__dst) != (size_t) -1)
++ if (__glibc_objsize (__dst) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__len))
+ return __mbstowcs_chk (__dst, __src, __len,
+- __bos (__dst) / sizeof (wchar_t));
++ __glibc_objsize (__dst) / sizeof (wchar_t));
+
+- if (__len > __bos (__dst) / sizeof (wchar_t))
++ if (__len > __glibc_objsize (__dst) / sizeof (wchar_t))
+ return __mbstowcs_chk_warn (__dst, __src, __len,
+- __bos (__dst) / sizeof (wchar_t));
++ (__glibc_objsize (__dst)
++ / sizeof (wchar_t)));
+ }
+ return __mbstowcs_alias (__dst, __src, __len);
+ }
+@@ -144,12 +149,13 @@ __fortify_function size_t
+ __NTH (wcstombs (char *__restrict __dst, const wchar_t *__restrict __src,
+ size_t __len))
+ {
+- if (__bos (__dst) != (size_t) -1)
++ if (__glibc_objsize (__dst) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__len))
+- return __wcstombs_chk (__dst, __src, __len, __bos (__dst));
+- if (__len > __bos (__dst))
+- return __wcstombs_chk_warn (__dst, __src, __len, __bos (__dst));
++ return __wcstombs_chk (__dst, __src, __len, __glibc_objsize (__dst));
++ if (__len > __glibc_objsize (__dst))
++ return __wcstombs_chk_warn (__dst, __src, __len,
++ __glibc_objsize (__dst));
+ }
+ return __wcstombs_alias (__dst, __src, __len);
+ }
+diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
+index d62b86de3e288d53..838ba877ee4b4afe 100644
+--- a/wcsmbs/bits/wchar2.h
++++ b/wcsmbs/bits/wchar2.h
+@@ -39,15 +39,15 @@ __fortify_function wchar_t *
+ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
+ size_t __n))
+ {
+- if (__bos0 (__s1) != (size_t) -1)
++ if (__glibc_objsize0 (__s1) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n))
+ return __wmemcpy_chk (__s1, __s2, __n,
+- __bos0 (__s1) / sizeof (wchar_t));
++ __glibc_objsize0 (__s1) / sizeof (wchar_t));
+
+- if (__n > __bos0 (__s1) / sizeof (wchar_t))
++ if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t))
+ return __wmemcpy_chk_warn (__s1, __s2, __n,
+- __bos0 (__s1) / sizeof (wchar_t));
++ __glibc_objsize0 (__s1) / sizeof (wchar_t));
+ }
+ return __wmemcpy_alias (__s1, __s2, __n);
+ }
+@@ -67,15 +67,16 @@ extern wchar_t *__REDIRECT_NTH (__wmemmove_chk_warn,
+ __fortify_function wchar_t *
+ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
+ {
+- if (__bos0 (__s1) != (size_t) -1)
++ if (__glibc_objsize0 (__s1) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n))
+ return __wmemmove_chk (__s1, __s2, __n,
+- __bos0 (__s1) / sizeof (wchar_t));
++ __glibc_objsize0 (__s1) / sizeof (wchar_t));
+
+- if (__n > __bos0 (__s1) / sizeof (wchar_t))
++ if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t))
+ return __wmemmove_chk_warn (__s1, __s2, __n,
+- __bos0 (__s1) / sizeof (wchar_t));
++ (__glibc_objsize0 (__s1)
++ / sizeof (wchar_t)));
+ }
+ return __wmemmove_alias (__s1, __s2, __n);
+ }
+@@ -100,15 +101,16 @@ __fortify_function wchar_t *
+ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
+ size_t __n))
+ {
+- if (__bos0 (__s1) != (size_t) -1)
++ if (__glibc_objsize0 (__s1) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n))
+ return __wmempcpy_chk (__s1, __s2, __n,
+- __bos0 (__s1) / sizeof (wchar_t));
++ __glibc_objsize0 (__s1) / sizeof (wchar_t));
+
+- if (__n > __bos0 (__s1) / sizeof (wchar_t))
++ if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t))
+ return __wmempcpy_chk_warn (__s1, __s2, __n,
+- __bos0 (__s1) / sizeof (wchar_t));
++ (__glibc_objsize0 (__s1)
++ / sizeof (wchar_t)));
+ }
+ return __wmempcpy_alias (__s1, __s2, __n);
+ }
+@@ -128,14 +130,15 @@ extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn,
+ __fortify_function wchar_t *
+ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
+ {
+- if (__bos0 (__s) != (size_t) -1)
++ if (__glibc_objsize0 (__s) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n))
+- return __wmemset_chk (__s, __c, __n, __bos0 (__s) / sizeof (wchar_t));
++ return __wmemset_chk (__s, __c, __n,
++ __glibc_objsize0 (__s) / sizeof (wchar_t));
+
+- if (__n > __bos0 (__s) / sizeof (wchar_t))
++ if (__n > __glibc_objsize0 (__s) / sizeof (wchar_t))
+ return __wmemset_chk_warn (__s, __c, __n,
+- __bos0 (__s) / sizeof (wchar_t));
++ __glibc_objsize0 (__s) / sizeof (wchar_t));
+ }
+ return __wmemset_alias (__s, __c, __n);
+ }
+@@ -151,8 +154,9 @@ extern wchar_t *__REDIRECT_NTH (__wcscpy_alias,
+ __fortify_function wchar_t *
+ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ {
+- if (__bos (__dest) != (size_t) -1)
+- return __wcscpy_chk (__dest, __src, __bos (__dest) / sizeof (wchar_t));
++ if (__glibc_objsize (__dest) != (size_t) -1)
++ return __wcscpy_chk (__dest, __src,
++ __glibc_objsize (__dest) / sizeof (wchar_t));
+ return __wcscpy_alias (__dest, __src);
+ }
+
+@@ -167,8 +171,9 @@ extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias,
+ __fortify_function wchar_t *
+ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ {
+- if (__bos (__dest) != (size_t) -1)
+- return __wcpcpy_chk (__dest, __src, __bos (__dest) / sizeof (wchar_t));
++ if (__glibc_objsize (__dest) != (size_t) -1)
++ return __wcpcpy_chk (__dest, __src,
++ __glibc_objsize (__dest) / sizeof (wchar_t));
+ return __wcpcpy_alias (__dest, __src);
+ }
+
+@@ -191,14 +196,15 @@ __fortify_function wchar_t *
+ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ size_t __n))
+ {
+- if (__bos (__dest) != (size_t) -1)
++ if (__glibc_objsize (__dest) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n))
+ return __wcsncpy_chk (__dest, __src, __n,
+- __bos (__dest) / sizeof (wchar_t));
+- if (__n > __bos (__dest) / sizeof (wchar_t))
++ __glibc_objsize (__dest) / sizeof (wchar_t));
++ if (__n > __glibc_objsize (__dest) / sizeof (wchar_t))
+ return __wcsncpy_chk_warn (__dest, __src, __n,
+- __bos (__dest) / sizeof (wchar_t));
++ (__glibc_objsize (__dest)
++ / sizeof (wchar_t)));
+ }
+ return __wcsncpy_alias (__dest, __src, __n);
+ }
+@@ -222,14 +228,15 @@ __fortify_function wchar_t *
+ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ size_t __n))
+ {
+- if (__bos (__dest) != (size_t) -1)
++ if (__glibc_objsize (__dest) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n))
+ return __wcpncpy_chk (__dest, __src, __n,
+- __bos (__dest) / sizeof (wchar_t));
+- if (__n > __bos (__dest) / sizeof (wchar_t))
++ __glibc_objsize (__dest) / sizeof (wchar_t));
++ if (__n > __glibc_objsize (__dest) / sizeof (wchar_t))
+ return __wcpncpy_chk_warn (__dest, __src, __n,
+- __bos (__dest) / sizeof (wchar_t));
++ (__glibc_objsize (__dest)
++ / sizeof (wchar_t)));
+ }
+ return __wcpncpy_alias (__dest, __src, __n);
+ }
+@@ -245,8 +252,9 @@ extern wchar_t *__REDIRECT_NTH (__wcscat_alias,
+ __fortify_function wchar_t *
+ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ {
+- if (__bos (__dest) != (size_t) -1)
+- return __wcscat_chk (__dest, __src, __bos (__dest) / sizeof (wchar_t));
++ if (__glibc_objsize (__dest) != (size_t) -1)
++ return __wcscat_chk (__dest, __src,
++ __glibc_objsize (__dest) / sizeof (wchar_t));
+ return __wcscat_alias (__dest, __src);
+ }
+
+@@ -263,9 +271,9 @@ __fortify_function wchar_t *
+ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ size_t __n))
+ {
+- if (__bos (__dest) != (size_t) -1)
++ if (__glibc_objsize (__dest) != (size_t) -1)
+ return __wcsncat_chk (__dest, __src, __n,
+- __bos (__dest) / sizeof (wchar_t));
++ __glibc_objsize (__dest) / sizeof (wchar_t));
+ return __wcsncat_alias (__dest, __src, __n);
+ }
+
+@@ -285,18 +293,18 @@ __fortify_function int
+ __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
+ const wchar_t *__restrict __fmt, ...))
+ {
+- if (__bos (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
++ if (__glibc_objsize (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
+ return __swprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
+- __bos (__s) / sizeof (wchar_t),
++ __glibc_objsize (__s) / sizeof (wchar_t),
+ __fmt, __va_arg_pack ());
+ return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ());
+ }
+ #elif !defined __cplusplus
+ /* XXX We might want to have support in gcc for swprintf. */
+ # define swprintf(s, n, ...) \
+- (__bos (s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1 \
++ (__glibc_objsize (s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1 \
+ ? __swprintf_chk (s, n, __USE_FORTIFY_LEVEL - 1, \
+- __bos (s) / sizeof (wchar_t), __VA_ARGS__) \
++ __glibc_objsize (s) / sizeof (wchar_t), __VA_ARGS__) \
+ : swprintf (s, n, __VA_ARGS__))
+ #endif
+
+@@ -315,9 +323,10 @@ __fortify_function int
+ __NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
+ const wchar_t *__restrict __fmt, __gnuc_va_list __ap))
+ {
+- if (__bos (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
++ if (__glibc_objsize (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
+ return __vswprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
+- __bos (__s) / sizeof (wchar_t), __fmt, __ap);
++ __glibc_objsize (__s) / sizeof (wchar_t), __fmt,
++ __ap);
+ return __vswprintf_alias (__s, __n, __fmt, __ap);
+ }
+
+@@ -383,14 +392,15 @@ extern wchar_t *__REDIRECT (__fgetws_chk_warn,
+ __fortify_function __wur wchar_t *
+ fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+ {
+- if (__bos (__s) != (size_t) -1)
++ if (__glibc_objsize (__s) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n) || __n <= 0)
+- return __fgetws_chk (__s, __bos (__s) / sizeof (wchar_t),
++ return __fgetws_chk (__s, __glibc_objsize (__s) / sizeof (wchar_t),
+ __n, __stream);
+
+- if ((size_t) __n > __bos (__s) / sizeof (wchar_t))
+- return __fgetws_chk_warn (__s, __bos (__s) / sizeof (wchar_t),
++ if ((size_t) __n > __glibc_objsize (__s) / sizeof (wchar_t))
++ return __fgetws_chk_warn (__s,
++ __glibc_objsize (__s) / sizeof (wchar_t),
+ __n, __stream);
+ }
+ return __fgetws_alias (__s, __n, __stream);
+@@ -414,14 +424,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)
+ {
+- if (__bos (__s) != (size_t) -1)
++ if (__glibc_objsize (__s) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__n) || __n <= 0)
+- return __fgetws_unlocked_chk (__s, __bos (__s) / sizeof (wchar_t),
++ return __fgetws_unlocked_chk (__s,
++ __glibc_objsize (__s) / sizeof (wchar_t),
+ __n, __stream);
+
+- if ((size_t) __n > __bos (__s) / sizeof (wchar_t))
+- return __fgetws_unlocked_chk_warn (__s, __bos (__s) / sizeof (wchar_t),
++ if ((size_t) __n > __glibc_objsize (__s) / sizeof (wchar_t))
++ return __fgetws_unlocked_chk_warn (__s,
++ (__glibc_objsize (__s)
++ / sizeof (wchar_t)),
+ __n, __stream);
+ }
+ return __fgetws_unlocked_alias (__s, __n, __stream);
+@@ -447,8 +460,9 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
+ #if defined MB_LEN_MAX && MB_LEN_MAX != __WCHAR_MB_LEN_MAX
+ # error "Assumed value of MB_LEN_MAX wrong"
+ #endif
+- if (__bos (__s) != (size_t) -1 && __WCHAR_MB_LEN_MAX > __bos (__s))
+- return __wcrtomb_chk (__s, __wchar, __ps, __bos (__s));
++ if (__glibc_objsize (__s) != (size_t) -1
++ && __WCHAR_MB_LEN_MAX > __glibc_objsize (__s))
++ return __wcrtomb_chk (__s, __wchar, __ps, __glibc_objsize (__s));
+ return __wcrtomb_alias (__s, __wchar, __ps);
+ }
+
+@@ -474,15 +488,16 @@ __fortify_function size_t
+ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
+ size_t __len, mbstate_t *__restrict __ps))
+ {
+- if (__bos (__dst) != (size_t) -1)
++ if (__glibc_objsize (__dst) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__len))
+ return __mbsrtowcs_chk (__dst, __src, __len, __ps,
+- __bos (__dst) / sizeof (wchar_t));
++ __glibc_objsize (__dst) / sizeof (wchar_t));
+
+- if (__len > __bos (__dst) / sizeof (wchar_t))
++ if (__len > __glibc_objsize (__dst) / sizeof (wchar_t))
+ return __mbsrtowcs_chk_warn (__dst, __src, __len, __ps,
+- __bos (__dst) / sizeof (wchar_t));
++ (__glibc_objsize (__dst)
++ / sizeof (wchar_t)));
+ }
+ return __mbsrtowcs_alias (__dst, __src, __len, __ps);
+ }
+@@ -508,13 +523,15 @@ __fortify_function size_t
+ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
+ size_t __len, mbstate_t *__restrict __ps))
+ {
+- if (__bos (__dst) != (size_t) -1)
++ if (__glibc_objsize (__dst) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__len))
+- return __wcsrtombs_chk (__dst, __src, __len, __ps, __bos (__dst));
++ return __wcsrtombs_chk (__dst, __src, __len, __ps,
++ __glibc_objsize (__dst));
+
+- if (__len > __bos (__dst))
+- return __wcsrtombs_chk_warn (__dst, __src, __len, __ps, __bos (__dst));
++ if (__len > __glibc_objsize (__dst))
++ return __wcsrtombs_chk_warn (__dst, __src, __len, __ps,
++ __glibc_objsize (__dst));
+ }
+ return __wcsrtombs_alias (__dst, __src, __len, __ps);
+ }
+@@ -542,15 +559,16 @@ __fortify_function size_t
+ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
+ size_t __nmc, size_t __len, mbstate_t *__restrict __ps))
+ {
+- if (__bos (__dst) != (size_t) -1)
++ if (__glibc_objsize (__dst) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__len))
+ return __mbsnrtowcs_chk (__dst, __src, __nmc, __len, __ps,
+- __bos (__dst) / sizeof (wchar_t));
++ __glibc_objsize (__dst) / sizeof (wchar_t));
+
+- if (__len > __bos (__dst) / sizeof (wchar_t))
++ if (__len > __glibc_objsize (__dst) / sizeof (wchar_t))
+ return __mbsnrtowcs_chk_warn (__dst, __src, __nmc, __len, __ps,
+- __bos (__dst) / sizeof (wchar_t));
++ (__glibc_objsize (__dst)
++ / sizeof (wchar_t)));
+ }
+ return __mbsnrtowcs_alias (__dst, __src, __nmc, __len, __ps);
+ }
+@@ -578,15 +596,15 @@ __fortify_function size_t
+ __NTH (wcsnrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
+ size_t __nwc, size_t __len, mbstate_t *__restrict __ps))
+ {
+- if (__bos (__dst) != (size_t) -1)
++ if (__glibc_objsize (__dst) != (size_t) -1)
+ {
+ if (!__builtin_constant_p (__len))
+ return __wcsnrtombs_chk (__dst, __src, __nwc, __len, __ps,
+- __bos (__dst));
++ __glibc_objsize (__dst));
+
+- if (__len > __bos (__dst))
++ if (__len > __glibc_objsize (__dst))
+ return __wcsnrtombs_chk_warn (__dst, __src, __nwc, __len, __ps,
+- __bos (__dst));
++ __glibc_objsize (__dst));
+ }
+ return __wcsnrtombs_alias (__dst, __src, __nwc, __len, __ps);
+ }
diff --git a/glibc-rh2033684-6.patch b/glibc-rh2033684-6.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b183d70bedb4f00b67360e75f271c1c1d26204a1
--- /dev/null
+++ b/glibc-rh2033684-6.patch
@@ -0,0 +1,1037 @@
+commit a643f60c53876be0d57b4b7373770e6cb356fd13
+Author: Siddhesh Poyarekar
+Date: Wed Oct 20 18:12:41 2021 +0530
+
+ Make sure that the fortified function conditionals are constant
+
+ In _FORTIFY_SOURCE=3, the size expression may be non-constant,
+ resulting in branches in the inline functions remaining intact and
+ causing a tiny overhead. Clang (and in future, gcc) make sure that
+ the -1 case is always safe, i.e. any comparison of the generated
+ expression with (size_t)-1 is always false so that bit is taken care
+ of. The rest is avoidable since we want the _chk variant whenever we
+ have a size expression and it's not -1.
+
+ Rework the conditionals in a uniform way to clearly indicate two
+ conditions at compile time:
+
+ - Either the size is unknown (-1) or we know at compile time that the
+ operation length is less than the object size. We can call the
+ original function in this case. It could be that either the length,
+ object size or both are non-constant, but the compiler, through
+ range analysis, is able to fold the *comparison* to a constant.
+
+ - The size and length are known and the compiler can see at compile
+ time that operation length > object size. This is valid grounds for
+ a warning at compile time, followed by emitting the _chk variant.
+
+ For everything else, emit the _chk variant.
+
+ This simplifies most of the fortified function implementations and at
+ the same time, ensures that only one call from _chk or the regular
+ function is emitted.
+
+ Signed-off-by: Siddhesh Poyarekar
+ Reviewed-by: Adhemerval Zanella
+
+diff --git a/io/bits/poll2.h b/io/bits/poll2.h
+index f47fd9ad0945234f..6f4dae77e5e2d0d3 100644
+--- a/io/bits/poll2.h
++++ b/io/bits/poll2.h
+@@ -35,16 +35,9 @@ extern int __REDIRECT (__poll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
+ __fortify_function int
+ poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+ {
+- if (__glibc_objsize (__fds) != (__SIZE_TYPE__) -1)
+- {
+- if (! __builtin_constant_p (__nfds))
+- return __poll_chk (__fds, __nfds, __timeout, __glibc_objsize (__fds));
+- else if (__glibc_objsize (__fds) / sizeof (*__fds) < __nfds)
+- return __poll_chk_warn (__fds, __nfds, __timeout,
+- __glibc_objsize (__fds));
+- }
+-
+- return __poll_alias (__fds, __nfds, __timeout);
++ return __glibc_fortify (poll, __nfds, sizeof (*__fds),
++ __glibc_objsize (__fds),
++ __fds, __nfds, __timeout);
+ }
+
+
+@@ -66,17 +59,9 @@ __fortify_function int
+ ppoll (struct pollfd *__fds, nfds_t __nfds, const struct timespec *__timeout,
+ const __sigset_t *__ss)
+ {
+- if (__glibc_objsize (__fds) != (__SIZE_TYPE__) -1)
+- {
+- if (! __builtin_constant_p (__nfds))
+- return __ppoll_chk (__fds, __nfds, __timeout, __ss,
+- __glibc_objsize (__fds));
+- else if (__glibc_objsize (__fds) / sizeof (*__fds) < __nfds)
+- return __ppoll_chk_warn (__fds, __nfds, __timeout, __ss,
+- __glibc_objsize (__fds));
+- }
+-
+- return __ppoll_alias (__fds, __nfds, __timeout, __ss);
++ return __glibc_fortify (ppoll, __nfds, sizeof (*__fds),
++ __glibc_objsize (__fds),
++ __fds, __nfds, __timeout, __ss);
+ }
+ #endif
+
+diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
+index 2cd69f44cfadfc9f..4630fe0256b1a562 100644
+--- a/libio/bits/stdio2.h
++++ b/libio/bits/stdio2.h
+@@ -256,15 +256,12 @@ extern char *__REDIRECT (__fgets_chk_warn,
+ __fortify_function __wur char *
+ fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
+ {
+- if (__glibc_objsize (__s) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n) || __n <= 0)
+- return __fgets_chk (__s, __glibc_objsize (__s), __n, __stream);
+-
+- if ((size_t) __n > __glibc_objsize (__s))
+- return __fgets_chk_warn (__s, __glibc_objsize (__s), __n, __stream);
+- }
+- return __fgets_alias (__s, __n, __stream);
++ 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);
+ }
+
+ extern size_t __fread_chk (void *__restrict __ptr, size_t __ptrlen,
+@@ -286,19 +283,12 @@ __fortify_function __wur size_t
+ fread (void *__restrict __ptr, size_t __size, size_t __n,
+ FILE *__restrict __stream)
+ {
+- if (__glibc_objsize0 (__ptr) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__size)
+- || !__builtin_constant_p (__n)
+- || (__size | __n) >= (((size_t) 1) << (8 * sizeof (size_t) / 2)))
+- return __fread_chk (__ptr, __glibc_objsize0 (__ptr), __size, __n,
+- __stream);
+-
+- if (__size * __n > __glibc_objsize0 (__ptr))
+- return __fread_chk_warn (__ptr, __glibc_objsize0 (__ptr), __size, __n,
+- __stream);
+- }
+- return __fread_alias (__ptr, __size, __n, __stream);
++ 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);
+ }
+
+ #ifdef __USE_GNU
+@@ -316,17 +306,12 @@ extern char *__REDIRECT (__fgets_unlocked_chk_warn,
+ __fortify_function __wur char *
+ fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream)
+ {
+- if (__glibc_objsize (__s) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n) || __n <= 0)
+- return __fgets_unlocked_chk (__s, __glibc_objsize (__s), __n,
+- __stream);
+-
+- if ((size_t) __n > __glibc_objsize (__s))
+- return __fgets_unlocked_chk_warn (__s, __glibc_objsize (__s), __n,
+- __stream);
+- }
+- return __fgets_unlocked_alias (__s, __n, __stream);
++ 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);
+ }
+ #endif
+
+@@ -351,41 +336,36 @@ __fortify_function __wur size_t
+ fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
+ FILE *__restrict __stream)
+ {
+- if (__glibc_objsize0 (__ptr) != (size_t) -1)
++ size_t sz = __glibc_objsize0 (__ptr);
++ if (__glibc_safe_or_unknown_len (__n, __size, sz))
+ {
+- if (!__builtin_constant_p (__size)
+- || !__builtin_constant_p (__n)
+- || (__size | __n) >= (((size_t) 1) << (8 * sizeof (size_t) / 2)))
+- return __fread_unlocked_chk (__ptr, __glibc_objsize0 (__ptr), __size,
+- __n, __stream);
+-
+- if (__size * __n > __glibc_objsize0 (__ptr))
+- return __fread_unlocked_chk_warn (__ptr, __glibc_objsize0 (__ptr),
+- __size, __n, __stream);
+- }
+-
+ # ifdef __USE_EXTERN_INLINES
+- if (__builtin_constant_p (__size)
+- && __builtin_constant_p (__n)
+- && (__size | __n) < (((size_t) 1) << (8 * sizeof (size_t) / 2))
+- && __size * __n <= 8)
+- {
+- size_t __cnt = __size * __n;
+- char *__cptr = (char *) __ptr;
+- if (__cnt == 0)
+- return 0;
+-
+- for (; __cnt > 0; --__cnt)
++ if (__builtin_constant_p (__size)
++ && __builtin_constant_p (__n)
++ && (__size | __n) < (((size_t) 1) << (8 * sizeof (size_t) / 2))
++ && __size * __n <= 8)
+ {
+- int __c = getc_unlocked (__stream);
+- if (__c == EOF)
+- break;
+- *__cptr++ = __c;
++ size_t __cnt = __size * __n;
++ char *__cptr = (char *) __ptr;
++ if (__cnt == 0)
++ return 0;
++
++ for (; __cnt > 0; --__cnt)
++ {
++ int __c = getc_unlocked (__stream);
++ if (__c == EOF)
++ break;
++ *__cptr++ = __c;
++ }
++ return (__cptr - (char *) __ptr) / __size;
+ }
+- return (__cptr - (char *) __ptr) / __size;
+- }
+ # endif
+- return __fread_unlocked_alias (__ptr, __size, __n, __stream);
++ 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);
++
+ }
+ #endif
+
+diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
+index 1e39307b0ebcf38f..17b84a2e6c69d961 100644
+--- a/misc/sys/cdefs.h
++++ b/misc/sys/cdefs.h
+@@ -132,6 +132,53 @@
+ # define __glibc_objsize(__o) __bos (__o)
+ #endif
+
++/* Compile time conditions to choose between the regular, _chk and _chk_warn
++ variants. These conditions should get evaluated to constant and optimized
++ away. */
++
++#define __glibc_safe_len_cond(__l, __s, __osz) ((__l) <= (__osz) / (__s))
++#define __glibc_unsigned_or_positive(__l) \
++ ((__typeof (__l)) 0 < (__typeof (__l)) -1 \
++ || (__builtin_constant_p (__l) && (__l) > 0))
++
++/* Length is known to be safe at compile time if the __L * __S <= __OBJSZ
++ condition can be folded to a constant and if it is true. The -1 check is
++ redundant because since it implies that __glibc_safe_len_cond is true. */
++#define __glibc_safe_or_unknown_len(__l, __s, __osz) \
++ (__glibc_unsigned_or_positive (__l) \
++ && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \
++ __s, __osz)) \
++ && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz))
++
++/* Conversely, we know at compile time that the length is safe if the
++ __L * __S <= __OBJSZ condition can be folded to a constant and if it is
++ false. */
++#define __glibc_unsafe_len(__l, __s, __osz) \
++ (__glibc_unsigned_or_positive (__l) \
++ && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \
++ __s, __osz)) \
++ && !__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz))
++
++/* Fortify function f. __f_alias, __f_chk and __f_chk_warn must be
++ declared. */
++
++#define __glibc_fortify(f, __l, __s, __osz, ...) \
++ (__glibc_safe_or_unknown_len (__l, __s, __osz) \
++ ? __ ## f ## _alias (__VA_ARGS__) \
++ : (__glibc_unsafe_len (__l, __s, __osz) \
++ ? __ ## f ## _chk_warn (__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. */
++
++#define __glibc_fortify_n(f, __l, __s, __osz, ...) \
++ (__glibc_safe_or_unknown_len (__l, __s, __osz) \
++ ? __ ## f ## _alias (__VA_ARGS__) \
++ : (__glibc_unsafe_len (__l, __s, __osz) \
++ ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s)) \
++ : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) \
++
+ #if __GNUC_PREREQ (4,3)
+ # define __warndecl(name, msg) \
+ extern void name (void) __attribute__((__warning__ (msg)))
+diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h
+index a0c4dcfe9c61a7b8..a456d1723547db70 100644
+--- a/posix/bits/unistd.h
++++ b/posix/bits/unistd.h
+@@ -33,16 +33,9 @@ extern ssize_t __REDIRECT (__read_chk_warn,
+ __fortify_function __wur ssize_t
+ read (int __fd, void *__buf, size_t __nbytes)
+ {
+- if (__glibc_objsize0 (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__nbytes))
+- return __read_chk (__fd, __buf, __nbytes, __glibc_objsize0 (__buf));
+-
+- if (__nbytes > __glibc_objsize0 (__buf))
+- return __read_chk_warn (__fd, __buf, __nbytes,
+- __glibc_objsize0 (__buf));
+- }
+- return __read_alias (__fd, __buf, __nbytes);
++ return __glibc_fortify (read, __nbytes, sizeof (char),
++ __glibc_objsize0 (__buf),
++ __fd, __buf, __nbytes);
+ }
+
+ #ifdef __USE_UNIX98
+@@ -72,34 +65,17 @@ extern ssize_t __REDIRECT (__pread64_chk_warn,
+ __fortify_function __wur ssize_t
+ pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset)
+ {
+- if (__glibc_objsize0 (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__nbytes))
+- return __pread_chk (__fd, __buf, __nbytes, __offset,
+- __glibc_objsize0 (__buf));
+-
+- if ( __nbytes > __glibc_objsize0 (__buf))
+- return __pread_chk_warn (__fd, __buf, __nbytes, __offset,
+- __glibc_objsize0 (__buf));
+- }
+- return __pread_alias (__fd, __buf, __nbytes, __offset);
++ return __glibc_fortify (pread, __nbytes, sizeof (char),
++ __glibc_objsize0 (__buf),
++ __fd, __buf, __nbytes, __offset);
+ }
+ # else
+ __fortify_function __wur ssize_t
+ pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+ {
+- if (__glibc_objsize0 (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__nbytes))
+- return __pread64_chk (__fd, __buf, __nbytes, __offset,
+- __glibc_objsize0 (__buf));
+-
+- if ( __nbytes > __glibc_objsize0 (__buf))
+- return __pread64_chk_warn (__fd, __buf, __nbytes, __offset,
+- __glibc_objsize0 (__buf));
+- }
+-
+- return __pread64_alias (__fd, __buf, __nbytes, __offset);
++ return __glibc_fortify (pread64, __nbytes, sizeof (char),
++ __glibc_objsize0 (__buf),
++ __fd, __buf, __nbytes, __offset);
+ }
+ # endif
+
+@@ -107,18 +83,9 @@ pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+ __fortify_function __wur ssize_t
+ pread64 (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+ {
+- if (__glibc_objsize0 (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__nbytes))
+- return __pread64_chk (__fd, __buf, __nbytes, __offset,
+- __glibc_objsize0 (__buf));
+-
+- if ( __nbytes > __glibc_objsize0 (__buf))
+- return __pread64_chk_warn (__fd, __buf, __nbytes, __offset,
+- __glibc_objsize0 (__buf));
+- }
+-
+- return __pread64_alias (__fd, __buf, __nbytes, __offset);
++ return __glibc_fortify (pread64, __nbytes, sizeof (char),
++ __glibc_objsize0 (__buf),
++ __fd, __buf, __nbytes, __offset);
+ }
+ # endif
+ #endif
+@@ -143,16 +110,9 @@ __fortify_function __nonnull ((1, 2)) __wur ssize_t
+ __NTH (readlink (const char *__restrict __path, char *__restrict __buf,
+ size_t __len))
+ {
+- if (__glibc_objsize (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__len))
+- return __readlink_chk (__path, __buf, __len, __glibc_objsize (__buf));
+-
+- if ( __len > __glibc_objsize (__buf))
+- return __readlink_chk_warn (__path, __buf, __len,
+- __glibc_objsize (__buf));
+- }
+- return __readlink_alias (__path, __buf, __len);
++ return __glibc_fortify (readlink, __len, sizeof (char),
++ __glibc_objsize (__buf),
++ __path, __buf, __len);
+ }
+ #endif
+
+@@ -178,17 +138,9 @@ __fortify_function __nonnull ((2, 3)) __wur ssize_t
+ __NTH (readlinkat (int __fd, const char *__restrict __path,
+ char *__restrict __buf, size_t __len))
+ {
+- if (__glibc_objsize (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__len))
+- return __readlinkat_chk (__fd, __path, __buf, __len,
+- __glibc_objsize (__buf));
+-
+- if (__len > __glibc_objsize (__buf))
+- return __readlinkat_chk_warn (__fd, __path, __buf, __len,
+- __glibc_objsize (__buf));
+- }
+- return __readlinkat_alias (__fd, __path, __buf, __len);
++ return __glibc_fortify (readlinkat, __len, sizeof (char),
++ __glibc_objsize (__buf),
++ __fd, __path, __buf, __len);
+ }
+ #endif
+
+@@ -205,15 +157,9 @@ extern char *__REDIRECT_NTH (__getcwd_chk_warn,
+ __fortify_function __wur char *
+ __NTH (getcwd (char *__buf, size_t __size))
+ {
+- if (__glibc_objsize (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__size))
+- return __getcwd_chk (__buf, __size, __glibc_objsize (__buf));
+-
+- if (__size > __glibc_objsize (__buf))
+- return __getcwd_chk_warn (__buf, __size, __glibc_objsize (__buf));
+- }
+- return __getcwd_alias (__buf, __size);
++ return __glibc_fortify (getcwd, __size, sizeof (char),
++ __glibc_objsize (__buf),
++ __buf, __size);
+ }
+
+ #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED
+@@ -245,16 +191,9 @@ extern size_t __REDIRECT_NTH (__confstr_chk_warn,
+ __fortify_function size_t
+ __NTH (confstr (int __name, char *__buf, size_t __len))
+ {
+- if (__glibc_objsize (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__len))
+- return __confstr_chk (__name, __buf, __len, __glibc_objsize (__buf));
+-
+- if (__glibc_objsize (__buf) < __len)
+- return __confstr_chk_warn (__name, __buf, __len,
+- __glibc_objsize (__buf));
+- }
+- return __confstr_alias (__name, __buf, __len);
++ return __glibc_fortify (confstr, __len, sizeof (char),
++ __glibc_objsize (__buf),
++ __name, __buf, __len);
+ }
+
+
+@@ -271,15 +210,9 @@ extern int __REDIRECT_NTH (__getgroups_chk_warn,
+ __fortify_function int
+ __NTH (getgroups (int __size, __gid_t __list[]))
+ {
+- if (__glibc_objsize (__list) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__size) || __size < 0)
+- return __getgroups_chk (__size, __list, __glibc_objsize (__list));
+-
+- if (__size * sizeof (__gid_t) > __glibc_objsize (__list))
+- return __getgroups_chk_warn (__size, __list, __glibc_objsize (__list));
+- }
+- return __getgroups_alias (__size, __list);
++ return __glibc_fortify (getgroups, __size, sizeof (__gid_t),
++ __glibc_objsize (__list),
++ __size, __list);
+ }
+
+
+@@ -297,17 +230,9 @@ extern int __REDIRECT_NTH (__ttyname_r_chk_warn,
+ __fortify_function int
+ __NTH (ttyname_r (int __fd, char *__buf, size_t __buflen))
+ {
+- if (__glibc_objsize (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__buflen))
+- return __ttyname_r_chk (__fd, __buf, __buflen,
+- __glibc_objsize (__buf));
+-
+- if (__buflen > __glibc_objsize (__buf))
+- return __ttyname_r_chk_warn (__fd, __buf, __buflen,
+- __glibc_objsize (__buf));
+- }
+- return __ttyname_r_alias (__fd, __buf, __buflen);
++ return __glibc_fortify (ttyname_r, __buflen, sizeof (char),
++ __glibc_objsize (__buf),
++ __fd, __buf, __buflen);
+ }
+
+
+@@ -325,16 +250,9 @@ extern int __REDIRECT (__getlogin_r_chk_warn,
+ __fortify_function int
+ getlogin_r (char *__buf, size_t __buflen)
+ {
+- if (__glibc_objsize (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__buflen))
+- return __getlogin_r_chk (__buf, __buflen, __glibc_objsize (__buf));
+-
+- if (__buflen > __glibc_objsize (__buf))
+- return __getlogin_r_chk_warn (__buf, __buflen,
+- __glibc_objsize (__buf));
+- }
+- return __getlogin_r_alias (__buf, __buflen);
++ return __glibc_fortify (getlogin_r, __buflen, sizeof (char),
++ __glibc_objsize (__buf),
++ __buf, __buflen);
+ }
+ #endif
+
+@@ -353,16 +271,9 @@ extern int __REDIRECT_NTH (__gethostname_chk_warn,
+ __fortify_function int
+ __NTH (gethostname (char *__buf, size_t __buflen))
+ {
+- if (__glibc_objsize (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__buflen))
+- return __gethostname_chk (__buf, __buflen, __glibc_objsize (__buf));
+-
+- if (__buflen > __glibc_objsize (__buf))
+- return __gethostname_chk_warn (__buf, __buflen,
+- __glibc_objsize (__buf));
+- }
+- return __gethostname_alias (__buf, __buflen);
++ return __glibc_fortify (gethostname, __buflen, sizeof (char),
++ __glibc_objsize (__buf),
++ __buf, __buflen);
+ }
+ #endif
+
+@@ -383,15 +294,8 @@ extern int __REDIRECT_NTH (__getdomainname_chk_warn,
+ __fortify_function int
+ __NTH (getdomainname (char *__buf, size_t __buflen))
+ {
+- if (__glibc_objsize (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__buflen))
+- return __getdomainname_chk (__buf, __buflen, __glibc_objsize (__buf));
+-
+- if (__buflen > __glibc_objsize (__buf))
+- return __getdomainname_chk_warn (__buf, __buflen,
+- __glibc_objsize (__buf));
+- }
+- return __getdomainname_alias (__buf, __buflen);
++ return __glibc_fortify (getdomainname, __buflen, sizeof (char),
++ __glibc_objsize (__buf),
++ __buf, __buflen);
+ }
+ #endif
+diff --git a/socket/bits/socket2.h b/socket/bits/socket2.h
+index 729e5a4cc1f4cb92..68fe5435b3b29c2a 100644
+--- a/socket/bits/socket2.h
++++ b/socket/bits/socket2.h
+@@ -33,17 +33,12 @@ extern ssize_t __REDIRECT (__recv_chk_warn,
+ __fortify_function ssize_t
+ recv (int __fd, void *__buf, size_t __n, int __flags)
+ {
+- if (__glibc_objsize0 (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n))
+- return __recv_chk (__fd, __buf, __n, __glibc_objsize0 (__buf),
+- __flags);
+-
+- if (__n > __glibc_objsize0 (__buf))
+- return __recv_chk_warn (__fd, __buf, __n, __glibc_objsize0 (__buf),
+- __flags);
+- }
+- return __recv_alias (__fd, __buf, __n, __flags);
++ 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);
+ }
+
+ extern ssize_t __recvfrom_chk (int __fd, void *__restrict __buf, size_t __n,
+@@ -66,14 +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)
+ {
+- if (__glibc_objsize0 (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n))
+- return __recvfrom_chk (__fd, __buf, __n, __glibc_objsize0 (__buf),
+- __flags, __addr, __addr_len);
+- if (__n > __glibc_objsize0 (__buf))
+- return __recvfrom_chk_warn (__fd, __buf, __n, __glibc_objsize0 (__buf),
+- __flags, __addr, __addr_len);
+- }
+- return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len);
++ 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,
++ __addr_len);
++ return __recvfrom_chk (__fd, __buf, __n, sz, __flags, __addr, __addr_len);
+ }
+diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
+index 5e4114ded33f2033..7ea364a276497720 100644
+--- a/stdlib/bits/stdlib.h
++++ b/stdlib/bits/stdlib.h
+@@ -36,17 +36,16 @@ extern char *__REDIRECT_NTH (__realpath_chk_warn,
+ __fortify_function __wur char *
+ __NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
+ {
+- if (__glibc_objsize (__resolved) != (size_t) -1)
+- {
++ size_t sz = __glibc_objsize (__resolved);
++
++ if (sz == (size_t) -1)
++ return __realpath_alias (__name, __resolved);
++
+ #if defined _LIBC_LIMITS_H_ && defined PATH_MAX
+- if (__glibc_objsize (__resolved) < PATH_MAX)
+- return __realpath_chk_warn (__name, __resolved,
+- __glibc_objsize (__resolved));
++ if (__glibc_unsafe_len (sz, sizeof (char), PATH_MAX))
++ return __realpath_chk_warn (__name, __resolved, sz);
+ #endif
+- return __realpath_chk (__name, __resolved, __glibc_objsize (__resolved));
+- }
+-
+- return __realpath_alias (__name, __resolved);
++ return __realpath_chk (__name, __resolved, sz);
+ }
+
+
+@@ -64,16 +63,9 @@ extern int __REDIRECT_NTH (__ptsname_r_chk_warn,
+ __fortify_function int
+ __NTH (ptsname_r (int __fd, char *__buf, size_t __buflen))
+ {
+- if (__glibc_objsize (__buf) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__buflen))
+- return __ptsname_r_chk (__fd, __buf, __buflen,
+- __glibc_objsize (__buf));
+- if (__buflen > __glibc_objsize (__buf))
+- return __ptsname_r_chk_warn (__fd, __buf, __buflen,
+- __glibc_objsize (__buf));
+- }
+- return __ptsname_r_alias (__fd, __buf, __buflen);
++ return __glibc_fortify (ptsname_r, __buflen, sizeof (char),
++ __glibc_objsize (__buf),
++ __fd, __buf, __buflen);
+ }
+
+
+@@ -117,18 +109,9 @@ __fortify_function size_t
+ __NTH (mbstowcs (wchar_t *__restrict __dst, const char *__restrict __src,
+ size_t __len))
+ {
+- if (__glibc_objsize (__dst) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__len))
+- return __mbstowcs_chk (__dst, __src, __len,
+- __glibc_objsize (__dst) / sizeof (wchar_t));
+-
+- if (__len > __glibc_objsize (__dst) / sizeof (wchar_t))
+- return __mbstowcs_chk_warn (__dst, __src, __len,
+- (__glibc_objsize (__dst)
+- / sizeof (wchar_t)));
+- }
+- return __mbstowcs_alias (__dst, __src, __len);
++ return __glibc_fortify_n (mbstowcs, __len, sizeof (wchar_t),
++ __glibc_objsize (__dst),
++ __dst, __src, __len);
+ }
+
+
+@@ -149,13 +132,7 @@ __fortify_function size_t
+ __NTH (wcstombs (char *__restrict __dst, const wchar_t *__restrict __src,
+ size_t __len))
+ {
+- if (__glibc_objsize (__dst) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__len))
+- return __wcstombs_chk (__dst, __src, __len, __glibc_objsize (__dst));
+- if (__len > __glibc_objsize (__dst))
+- return __wcstombs_chk_warn (__dst, __src, __len,
+- __glibc_objsize (__dst));
+- }
+- return __wcstombs_alias (__dst, __src, __len);
++ return __glibc_fortify (wcstombs, __len, sizeof (char),
++ __glibc_objsize (__dst),
++ __dst, __src, __len);
+ }
+diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
+index 838ba877ee4b4afe..f82bba481981e4fb 100644
+--- a/wcsmbs/bits/wchar2.h
++++ b/wcsmbs/bits/wchar2.h
+@@ -39,17 +39,9 @@ __fortify_function wchar_t *
+ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
+ size_t __n))
+ {
+- if (__glibc_objsize0 (__s1) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n))
+- return __wmemcpy_chk (__s1, __s2, __n,
+- __glibc_objsize0 (__s1) / sizeof (wchar_t));
+-
+- if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t))
+- return __wmemcpy_chk_warn (__s1, __s2, __n,
+- __glibc_objsize0 (__s1) / sizeof (wchar_t));
+- }
+- return __wmemcpy_alias (__s1, __s2, __n);
++ return __glibc_fortify_n (wmemcpy, __n, sizeof (wchar_t),
++ __glibc_objsize0 (__s1),
++ __s1, __s2, __n);
+ }
+
+
+@@ -67,18 +59,9 @@ extern wchar_t *__REDIRECT_NTH (__wmemmove_chk_warn,
+ __fortify_function wchar_t *
+ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
+ {
+- if (__glibc_objsize0 (__s1) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n))
+- return __wmemmove_chk (__s1, __s2, __n,
+- __glibc_objsize0 (__s1) / sizeof (wchar_t));
+-
+- if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t))
+- return __wmemmove_chk_warn (__s1, __s2, __n,
+- (__glibc_objsize0 (__s1)
+- / sizeof (wchar_t)));
+- }
+- return __wmemmove_alias (__s1, __s2, __n);
++ return __glibc_fortify_n (wmemmove, __n, sizeof (wchar_t),
++ __glibc_objsize0 (__s1),
++ __s1, __s2, __n);
+ }
+
+
+@@ -101,18 +84,9 @@ __fortify_function wchar_t *
+ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
+ size_t __n))
+ {
+- if (__glibc_objsize0 (__s1) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n))
+- return __wmempcpy_chk (__s1, __s2, __n,
+- __glibc_objsize0 (__s1) / sizeof (wchar_t));
+-
+- if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t))
+- return __wmempcpy_chk_warn (__s1, __s2, __n,
+- (__glibc_objsize0 (__s1)
+- / sizeof (wchar_t)));
+- }
+- return __wmempcpy_alias (__s1, __s2, __n);
++ return __glibc_fortify_n (wmempcpy, __n, sizeof (wchar_t),
++ __glibc_objsize0 (__s1),
++ __s1, __s2, __n);
+ }
+ #endif
+
+@@ -130,17 +104,9 @@ extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn,
+ __fortify_function wchar_t *
+ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
+ {
+- if (__glibc_objsize0 (__s) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n))
+- return __wmemset_chk (__s, __c, __n,
+- __glibc_objsize0 (__s) / sizeof (wchar_t));
+-
+- if (__n > __glibc_objsize0 (__s) / sizeof (wchar_t))
+- return __wmemset_chk_warn (__s, __c, __n,
+- __glibc_objsize0 (__s) / sizeof (wchar_t));
+- }
+- return __wmemset_alias (__s, __c, __n);
++ return __glibc_fortify_n (wmemset, __n, sizeof (wchar_t),
++ __glibc_objsize0 (__s),
++ __s, __c, __n);
+ }
+
+
+@@ -154,9 +120,9 @@ extern wchar_t *__REDIRECT_NTH (__wcscpy_alias,
+ __fortify_function wchar_t *
+ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ {
+- if (__glibc_objsize (__dest) != (size_t) -1)
+- return __wcscpy_chk (__dest, __src,
+- __glibc_objsize (__dest) / 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);
+ }
+
+@@ -171,9 +137,9 @@ extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias,
+ __fortify_function wchar_t *
+ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ {
+- if (__glibc_objsize (__dest) != (size_t) -1)
+- return __wcpcpy_chk (__dest, __src,
+- __glibc_objsize (__dest) / 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);
+ }
+
+@@ -196,17 +162,9 @@ __fortify_function wchar_t *
+ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ size_t __n))
+ {
+- if (__glibc_objsize (__dest) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n))
+- return __wcsncpy_chk (__dest, __src, __n,
+- __glibc_objsize (__dest) / sizeof (wchar_t));
+- if (__n > __glibc_objsize (__dest) / sizeof (wchar_t))
+- return __wcsncpy_chk_warn (__dest, __src, __n,
+- (__glibc_objsize (__dest)
+- / sizeof (wchar_t)));
+- }
+- return __wcsncpy_alias (__dest, __src, __n);
++ return __glibc_fortify_n (wcsncpy, __n, sizeof (wchar_t),
++ __glibc_objsize (__dest),
++ __dest, __src, __n);
+ }
+
+
+@@ -228,17 +186,9 @@ __fortify_function wchar_t *
+ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ size_t __n))
+ {
+- if (__glibc_objsize (__dest) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n))
+- return __wcpncpy_chk (__dest, __src, __n,
+- __glibc_objsize (__dest) / sizeof (wchar_t));
+- if (__n > __glibc_objsize (__dest) / sizeof (wchar_t))
+- return __wcpncpy_chk_warn (__dest, __src, __n,
+- (__glibc_objsize (__dest)
+- / sizeof (wchar_t)));
+- }
+- return __wcpncpy_alias (__dest, __src, __n);
++ return __glibc_fortify_n (wcpncpy, __n, sizeof (wchar_t),
++ __glibc_objsize (__dest),
++ __dest, __src, __n);
+ }
+
+
+@@ -252,9 +202,9 @@ extern wchar_t *__REDIRECT_NTH (__wcscat_alias,
+ __fortify_function wchar_t *
+ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ {
+- if (__glibc_objsize (__dest) != (size_t) -1)
+- return __wcscat_chk (__dest, __src,
+- __glibc_objsize (__dest) / 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);
+ }
+
+@@ -271,9 +221,9 @@ __fortify_function wchar_t *
+ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ size_t __n))
+ {
+- if (__glibc_objsize (__dest) != (size_t) -1)
+- return __wcsncat_chk (__dest, __src, __n,
+- __glibc_objsize (__dest) / 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);
+ }
+
+@@ -293,10 +243,10 @@ __fortify_function int
+ __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
+ const wchar_t *__restrict __fmt, ...))
+ {
+- if (__glibc_objsize (__s) != (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,
+- __glibc_objsize (__s) / 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
+@@ -323,10 +273,10 @@ __fortify_function int
+ __NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
+ const wchar_t *__restrict __fmt, __gnuc_va_list __ap))
+ {
+- if (__glibc_objsize (__s) != (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,
+- __glibc_objsize (__s) / sizeof (wchar_t), __fmt,
+- __ap);
++ sz / sizeof (wchar_t), __fmt, __ap);
+ return __vswprintf_alias (__s, __n, __fmt, __ap);
+ }
+
+@@ -392,18 +342,12 @@ extern wchar_t *__REDIRECT (__fgetws_chk_warn,
+ __fortify_function __wur wchar_t *
+ fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+ {
+- if (__glibc_objsize (__s) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n) || __n <= 0)
+- return __fgetws_chk (__s, __glibc_objsize (__s) / sizeof (wchar_t),
+- __n, __stream);
+-
+- if ((size_t) __n > __glibc_objsize (__s) / sizeof (wchar_t))
+- return __fgetws_chk_warn (__s,
+- __glibc_objsize (__s) / sizeof (wchar_t),
+- __n, __stream);
+- }
+- return __fgetws_alias (__s, __n, __stream);
++ 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);
+ }
+
+ #ifdef __USE_GNU
+@@ -424,20 +368,13 @@ extern wchar_t *__REDIRECT (__fgetws_unlocked_chk_warn,
+ __fortify_function __wur wchar_t *
+ fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+ {
+- if (__glibc_objsize (__s) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__n) || __n <= 0)
+- return __fgetws_unlocked_chk (__s,
+- __glibc_objsize (__s) / sizeof (wchar_t),
+- __n, __stream);
+-
+- if ((size_t) __n > __glibc_objsize (__s) / sizeof (wchar_t))
+- return __fgetws_unlocked_chk_warn (__s,
+- (__glibc_objsize (__s)
+- / sizeof (wchar_t)),
+- __n, __stream);
+- }
+- return __fgetws_unlocked_alias (__s, __n, __stream);
++ 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,
++ __stream);
++ return __fgetws_unlocked_chk (__s, sz / sizeof (wchar_t), __n, __stream);
+ }
+ #endif
+
+@@ -488,18 +425,9 @@ __fortify_function size_t
+ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
+ size_t __len, mbstate_t *__restrict __ps))
+ {
+- if (__glibc_objsize (__dst) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__len))
+- return __mbsrtowcs_chk (__dst, __src, __len, __ps,
+- __glibc_objsize (__dst) / sizeof (wchar_t));
+-
+- if (__len > __glibc_objsize (__dst) / sizeof (wchar_t))
+- return __mbsrtowcs_chk_warn (__dst, __src, __len, __ps,
+- (__glibc_objsize (__dst)
+- / sizeof (wchar_t)));
+- }
+- return __mbsrtowcs_alias (__dst, __src, __len, __ps);
++ return __glibc_fortify_n (mbsrtowcs, __len, sizeof (wchar_t),
++ __glibc_objsize (__dst),
++ __dst, __src, __len, __ps);
+ }
+
+
+@@ -523,17 +451,9 @@ __fortify_function size_t
+ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
+ size_t __len, mbstate_t *__restrict __ps))
+ {
+- if (__glibc_objsize (__dst) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__len))
+- return __wcsrtombs_chk (__dst, __src, __len, __ps,
+- __glibc_objsize (__dst));
+-
+- if (__len > __glibc_objsize (__dst))
+- return __wcsrtombs_chk_warn (__dst, __src, __len, __ps,
+- __glibc_objsize (__dst));
+- }
+- return __wcsrtombs_alias (__dst, __src, __len, __ps);
++ return __glibc_fortify (wcsrtombs, __len, sizeof (char),
++ __glibc_objsize (__dst),
++ __dst, __src, __len, __ps);
+ }
+
+
+@@ -559,18 +479,9 @@ __fortify_function size_t
+ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
+ size_t __nmc, size_t __len, mbstate_t *__restrict __ps))
+ {
+- if (__glibc_objsize (__dst) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__len))
+- return __mbsnrtowcs_chk (__dst, __src, __nmc, __len, __ps,
+- __glibc_objsize (__dst) / sizeof (wchar_t));
+-
+- if (__len > __glibc_objsize (__dst) / sizeof (wchar_t))
+- return __mbsnrtowcs_chk_warn (__dst, __src, __nmc, __len, __ps,
+- (__glibc_objsize (__dst)
+- / sizeof (wchar_t)));
+- }
+- return __mbsnrtowcs_alias (__dst, __src, __nmc, __len, __ps);
++ return __glibc_fortify_n (mbsnrtowcs, __len, sizeof (wchar_t),
++ __glibc_objsize (__dst),
++ __dst, __src, __nmc, __len, __ps);
+ }
+
+
+@@ -596,16 +507,8 @@ __fortify_function size_t
+ __NTH (wcsnrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
+ size_t __nwc, size_t __len, mbstate_t *__restrict __ps))
+ {
+- if (__glibc_objsize (__dst) != (size_t) -1)
+- {
+- if (!__builtin_constant_p (__len))
+- return __wcsnrtombs_chk (__dst, __src, __nwc, __len, __ps,
+- __glibc_objsize (__dst));
+-
+- if (__len > __glibc_objsize (__dst))
+- return __wcsnrtombs_chk_warn (__dst, __src, __nwc, __len, __ps,
+- __glibc_objsize (__dst));
+- }
+- return __wcsnrtombs_alias (__dst, __src, __nwc, __len, __ps);
++ return __glibc_fortify (wcsnrtombs, __len, sizeof (char),
++ __glibc_objsize (__dst),
++ __dst, __src, __nwc, __len, __ps);
+ }
+ #endif
diff --git a/glibc-rh2033684-7.patch b/glibc-rh2033684-7.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7cb18a6887bbd0af7c87a24919c3704854f95a7f
--- /dev/null
+++ b/glibc-rh2033684-7.patch
@@ -0,0 +1,43 @@
+commit fadf75c370494da6a02274ebe79e45b2f22ebbd0
+Author: Florian Weimer
+Date: Mon Feb 10 14:37:10 2020 +0100
+
+ debug: Add missing locale dependencies of fortify tests
+
+ The missing dependencies result in failures like this if make check
+ is invoked with sufficient parallelism for the debug subdirectory:
+
+ FAIL: debug/tst-chk2
+ FAIL: debug/tst-chk3
+ FAIL: debug/tst-chk4
+ FAIL: debug/tst-chk5
+ FAIL: debug/tst-chk6
+ FAIL: debug/tst-lfschk1
+ FAIL: debug/tst-lfschk2
+ FAIL: debug/tst-lfschk3
+ FAIL: debug/tst-lfschk4
+ FAIL: debug/tst-lfschk5
+ FAIL: debug/tst-lfschk6
+
+diff --git a/debug/Makefile b/debug/Makefile
+index 506cebc3c4ca19ff..5e45c9b41077f2fd 100644
+--- a/debug/Makefile
++++ b/debug/Makefile
+@@ -188,6 +188,17 @@ LOCALES := de_DE.UTF-8
+ include ../gen-locales.mk
+
+ $(objpfx)tst-chk1.out: $(gen-locales)
++$(objpfx)tst-chk2.out: $(gen-locales)
++$(objpfx)tst-chk3.out: $(gen-locales)
++$(objpfx)tst-chk4.out: $(gen-locales)
++$(objpfx)tst-chk5.out: $(gen-locales)
++$(objpfx)tst-chk6.out: $(gen-locales)
++$(objpfx)tst-lfschk1.out: $(gen-locales)
++$(objpfx)tst-lfschk2.out: $(gen-locales)
++$(objpfx)tst-lfschk3.out: $(gen-locales)
++$(objpfx)tst-lfschk4.out: $(gen-locales)
++$(objpfx)tst-lfschk5.out: $(gen-locales)
++$(objpfx)tst-lfschk6.out: $(gen-locales)
+ endif
+
+ sLIBdir := $(shell echo $(slibdir) | sed 's,lib\(\|64\)$$,\\\\$$LIB,')
diff --git a/glibc-rh2033684-8.patch b/glibc-rh2033684-8.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5b90b20b66f30c9782c6af4b50d434e90da51928
--- /dev/null
+++ b/glibc-rh2033684-8.patch
@@ -0,0 +1,357 @@
+commit ad6f2a010c2ce759936de4747f6e0d53991912f8
+Author: Siddhesh Poyarekar
+Date: Wed Oct 20 18:13:05 2021 +0530
+
+ debug: Add tests for _FORTIFY_SOURCE=3
+
+ Add some testing coverage for _FORTIFY_SOURCE=3.
+
+ Signed-off-by: Siddhesh Poyarekar
+ Reviewed-by: Adhemerval Zanella
+
+diff --git a/debug/Makefile b/debug/Makefile
+index 5e45c9b41077f2fd..81361438fc3d2aa9 100644
+--- a/debug/Makefile
++++ b/debug/Makefile
+@@ -120,6 +120,8 @@ CFLAGS-tst-chk3.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+ CFLAGS-tst-chk4.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+ CFLAGS-tst-chk5.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+ CFLAGS-tst-chk6.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
++CFLAGS-tst-chk7.c += -Wno-format -Wno-deprecated-declarations -Wno-error
++CFLAGS-tst-chk8.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+ CFLAGS-tst-lfschk1.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+ CFLAGS-tst-lfschk2.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+ CFLAGS-tst-lfschk3.c += -Wno-format -Wno-deprecated-declarations -Wno-error
+@@ -129,6 +131,7 @@ CFLAGS-tst-lfschk6.cc += -Wno-format -Wno-deprecated-declarations -Wno-error
+ LDLIBS-tst-chk4 = -lstdc++
+ LDLIBS-tst-chk5 = -lstdc++
+ LDLIBS-tst-chk6 = -lstdc++
++LDLIBS-tst-chk8 = -lstdc++
+ LDLIBS-tst-lfschk4 = -lstdc++
+ LDLIBS-tst-lfschk5 = -lstdc++
+ LDLIBS-tst-lfschk6 = -lstdc++
+@@ -150,16 +153,16 @@ CFLAGS-tst-ssp-1.c += -fstack-protector-all
+
+ tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \
+ tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \
+- tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \
+- tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \
+- tst-backtrace5 tst-backtrace6
++ tst-chk4 tst-chk5 tst-chk6 tst-chk7 tst-chk8 tst-lfschk4 tst-lfschk5 \
++ tst-lfschk6 tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 \
++ tst-backtrace4 tst-backtrace5 tst-backtrace6
+
+ ifeq ($(have-ssp),yes)
+ tests += tst-ssp-1
+ endif
+
+ ifeq (,$(CXX))
+-tests-unsupported = tst-chk4 tst-chk5 tst-chk6 \
++tests-unsupported = tst-chk4 tst-chk5 tst-chk6 tst-chk8 \
+ tst-lfschk4 tst-lfschk5 tst-lfschk6
+ endif
+
+@@ -193,6 +196,8 @@ $(objpfx)tst-chk3.out: $(gen-locales)
+ $(objpfx)tst-chk4.out: $(gen-locales)
+ $(objpfx)tst-chk5.out: $(gen-locales)
+ $(objpfx)tst-chk6.out: $(gen-locales)
++$(objpfx)tst-chk7.out: $(gen-locales)
++$(objpfx)tst-chk8.out: $(gen-locales)
+ $(objpfx)tst-lfschk1.out: $(gen-locales)
+ $(objpfx)tst-lfschk2.out: $(gen-locales)
+ $(objpfx)tst-lfschk3.out: $(gen-locales)
+diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c
+index ca2b524b2fa6404c..5e76081255316a93 100644
+--- a/debug/tst-chk1.c
++++ b/debug/tst-chk1.c
+@@ -83,8 +83,14 @@ handler (int sig)
+ _exit (127);
+ }
+
++#if __USE_FORTIFY_LEVEL == 3
++volatile size_t buf_size = 10;
++#else
+ char buf[10];
+ wchar_t wbuf[10];
++#define buf_size sizeof (buf)
++#endif
++
+ volatile size_t l0;
+ volatile char *p;
+ volatile wchar_t *wp;
+@@ -123,6 +129,10 @@ int num2 = 987654;
+ static int
+ do_test (void)
+ {
++#if __USE_FORTIFY_LEVEL == 3
++ char *buf = (char *) malloc (buf_size);
++ wchar_t *wbuf = (wchar_t *) malloc (buf_size * sizeof (wchar_t));
++#endif
+ set_fortify_handler (handler);
+
+ struct A { char buf1[9]; char buf2[1]; } a;
+@@ -947,93 +957,93 @@ do_test (void)
+
+ rewind (stdin);
+
+- if (fgets (buf, sizeof (buf), stdin) != buf
++ if (fgets (buf, buf_size, stdin) != buf
+ || memcmp (buf, "abcdefgh\n", 10))
+ FAIL ();
+- if (fgets (buf, sizeof (buf), stdin) != buf || memcmp (buf, "ABCDEFGHI", 10))
++ if (fgets (buf, buf_size, stdin) != buf || memcmp (buf, "ABCDEFGHI", 10))
+ FAIL ();
+
+ rewind (stdin);
+
+- if (fgets (buf, l0 + sizeof (buf), stdin) != buf
++ if (fgets (buf, l0 + buf_size, stdin) != buf
+ || memcmp (buf, "abcdefgh\n", 10))
+ FAIL ();
+
+ #if __USE_FORTIFY_LEVEL >= 1
+ CHK_FAIL_START
+- if (fgets (buf, sizeof (buf) + 1, stdin) != buf)
++ if (fgets (buf, buf_size + 1, stdin) != buf)
+ FAIL ();
+ CHK_FAIL_END
+
+ CHK_FAIL_START
+- if (fgets (buf, l0 + sizeof (buf) + 1, stdin) != buf)
++ if (fgets (buf, l0 + buf_size + 1, stdin) != buf)
+ FAIL ();
+ CHK_FAIL_END
+ #endif
+
+ rewind (stdin);
+
+- if (fgets_unlocked (buf, sizeof (buf), stdin) != buf
++ if (fgets_unlocked (buf, buf_size, stdin) != buf
+ || memcmp (buf, "abcdefgh\n", 10))
+ FAIL ();
+- if (fgets_unlocked (buf, sizeof (buf), stdin) != buf
++ if (fgets_unlocked (buf, buf_size, stdin) != buf
+ || memcmp (buf, "ABCDEFGHI", 10))
+ FAIL ();
+
+ rewind (stdin);
+
+- if (fgets_unlocked (buf, l0 + sizeof (buf), stdin) != buf
++ if (fgets_unlocked (buf, l0 + buf_size, stdin) != buf
+ || memcmp (buf, "abcdefgh\n", 10))
+ FAIL ();
+
+ #if __USE_FORTIFY_LEVEL >= 1
+ CHK_FAIL_START
+- if (fgets_unlocked (buf, sizeof (buf) + 1, stdin) != buf)
++ if (fgets_unlocked (buf, buf_size + 1, stdin) != buf)
+ FAIL ();
+ CHK_FAIL_END
+
+ CHK_FAIL_START
+- if (fgets_unlocked (buf, l0 + sizeof (buf) + 1, stdin) != buf)
++ if (fgets_unlocked (buf, l0 + buf_size + 1, stdin) != buf)
+ FAIL ();
+ CHK_FAIL_END
+ #endif
+
+ rewind (stdin);
+
+- if (fread (buf, 1, sizeof (buf), stdin) != sizeof (buf)
++ if (fread (buf, 1, buf_size, stdin) != buf_size
+ || memcmp (buf, "abcdefgh\nA", 10))
+ FAIL ();
+- if (fread (buf, sizeof (buf), 1, stdin) != 1
++ if (fread (buf, buf_size, 1, stdin) != 1
+ || memcmp (buf, "BCDEFGHI\na", 10))
+ FAIL ();
+
+ rewind (stdin);
+
+- if (fread (buf, l0 + 1, sizeof (buf), stdin) != sizeof (buf)
++ if (fread (buf, l0 + 1, buf_size, stdin) != buf_size
+ || memcmp (buf, "abcdefgh\nA", 10))
+ FAIL ();
+- if (fread (buf, sizeof (buf), l0 + 1, stdin) != 1
++ if (fread (buf, buf_size, l0 + 1, stdin) != 1
+ || memcmp (buf, "BCDEFGHI\na", 10))
+ FAIL ();
+
+ #if __USE_FORTIFY_LEVEL >= 1
+ CHK_FAIL_START
+- if (fread (buf, 1, sizeof (buf) + 1, stdin) != sizeof (buf) + 1)
++ if (fread (buf, 1, buf_size + 1, stdin) != buf_size + 1)
+ FAIL ();
+ CHK_FAIL_END
+
+ CHK_FAIL_START
+- if (fread (buf, sizeof (buf) + 1, l0 + 1, stdin) != 1)
++ if (fread (buf, buf_size + 1, l0 + 1, stdin) != 1)
+ FAIL ();
+ CHK_FAIL_END
+ #endif
+
+ rewind (stdin);
+
+- if (fread_unlocked (buf, 1, sizeof (buf), stdin) != sizeof (buf)
++ if (fread_unlocked (buf, 1, buf_size, stdin) != buf_size
+ || memcmp (buf, "abcdefgh\nA", 10))
+ FAIL ();
+- if (fread_unlocked (buf, sizeof (buf), 1, stdin) != 1
++ if (fread_unlocked (buf, buf_size, 1, stdin) != 1
+ || memcmp (buf, "BCDEFGHI\na", 10))
+ FAIL ();
+
+@@ -1048,100 +1058,100 @@ do_test (void)
+
+ rewind (stdin);
+
+- if (fread_unlocked (buf, l0 + 1, sizeof (buf), stdin) != sizeof (buf)
++ if (fread_unlocked (buf, l0 + 1, buf_size, stdin) != buf_size
+ || memcmp (buf, "abcdefgh\nA", 10))
+ FAIL ();
+- if (fread_unlocked (buf, sizeof (buf), l0 + 1, stdin) != 1
++ if (fread_unlocked (buf, buf_size, l0 + 1, stdin) != 1
+ || memcmp (buf, "BCDEFGHI\na", 10))
+ FAIL ();
+
+ #if __USE_FORTIFY_LEVEL >= 1
+ CHK_FAIL_START
+- if (fread_unlocked (buf, 1, sizeof (buf) + 1, stdin) != sizeof (buf) + 1)
++ if (fread_unlocked (buf, 1, buf_size + 1, stdin) != buf_size + 1)
+ FAIL ();
+ CHK_FAIL_END
+
+ CHK_FAIL_START
+- if (fread_unlocked (buf, sizeof (buf) + 1, l0 + 1, stdin) != 1)
++ if (fread_unlocked (buf, buf_size + 1, l0 + 1, stdin) != 1)
+ FAIL ();
+ CHK_FAIL_END
+ #endif
+
+ lseek (fileno (stdin), 0, SEEK_SET);
+
+- if (read (fileno (stdin), buf, sizeof (buf) - 1) != sizeof (buf) - 1
++ if (read (fileno (stdin), buf, buf_size - 1) != buf_size - 1
+ || memcmp (buf, "abcdefgh\n", 9))
+ FAIL ();
+- if (read (fileno (stdin), buf, sizeof (buf) - 1) != sizeof (buf) - 1
++ if (read (fileno (stdin), buf, buf_size - 1) != buf_size - 1
+ || memcmp (buf, "ABCDEFGHI", 9))
+ FAIL ();
+
+ lseek (fileno (stdin), 0, SEEK_SET);
+
+- if (read (fileno (stdin), buf, l0 + sizeof (buf) - 1) != sizeof (buf) - 1
++ if (read (fileno (stdin), buf, l0 + buf_size - 1) != buf_size - 1
+ || memcmp (buf, "abcdefgh\n", 9))
+ FAIL ();
+
+ #if __USE_FORTIFY_LEVEL >= 1
+ CHK_FAIL_START
+- if (read (fileno (stdin), buf, sizeof (buf) + 1) != sizeof (buf) + 1)
++ if (read (fileno (stdin), buf, buf_size + 1) != buf_size + 1)
+ FAIL ();
+ CHK_FAIL_END
+
+ CHK_FAIL_START
+- if (read (fileno (stdin), buf, l0 + sizeof (buf) + 1) != sizeof (buf) + 1)
++ if (read (fileno (stdin), buf, l0 + buf_size + 1) != buf_size + 1)
+ FAIL ();
+ CHK_FAIL_END
+ #endif
+
+- if (pread (fileno (stdin), buf, sizeof (buf) - 1, sizeof (buf) - 2)
+- != sizeof (buf) - 1
++ if (pread (fileno (stdin), buf, buf_size - 1, buf_size - 2)
++ != buf_size - 1
+ || memcmp (buf, "\nABCDEFGH", 9))
+ FAIL ();
+- if (pread (fileno (stdin), buf, sizeof (buf) - 1, 0) != sizeof (buf) - 1
++ if (pread (fileno (stdin), buf, buf_size - 1, 0) != buf_size - 1
+ || memcmp (buf, "abcdefgh\n", 9))
+ FAIL ();
+- if (pread (fileno (stdin), buf, l0 + sizeof (buf) - 1, sizeof (buf) - 3)
+- != sizeof (buf) - 1
++ if (pread (fileno (stdin), buf, l0 + buf_size - 1, buf_size - 3)
++ != buf_size - 1
+ || memcmp (buf, "h\nABCDEFG", 9))
+ FAIL ();
+
+ #if __USE_FORTIFY_LEVEL >= 1
+ CHK_FAIL_START
+- if (pread (fileno (stdin), buf, sizeof (buf) + 1, 2 * sizeof (buf))
+- != sizeof (buf) + 1)
++ if (pread (fileno (stdin), buf, buf_size + 1, 2 * buf_size)
++ != buf_size + 1)
+ FAIL ();
+ CHK_FAIL_END
+
+ CHK_FAIL_START
+- if (pread (fileno (stdin), buf, l0 + sizeof (buf) + 1, 2 * sizeof (buf))
+- != sizeof (buf) + 1)
++ if (pread (fileno (stdin), buf, l0 + buf_size + 1, 2 * buf_size)
++ != buf_size + 1)
+ FAIL ();
+ CHK_FAIL_END
+ #endif
+
+- if (pread64 (fileno (stdin), buf, sizeof (buf) - 1, sizeof (buf) - 2)
+- != sizeof (buf) - 1
++ if (pread64 (fileno (stdin), buf, buf_size - 1, buf_size - 2)
++ != buf_size - 1
+ || memcmp (buf, "\nABCDEFGH", 9))
+ FAIL ();
+- if (pread64 (fileno (stdin), buf, sizeof (buf) - 1, 0) != sizeof (buf) - 1
++ if (pread64 (fileno (stdin), buf, buf_size - 1, 0) != buf_size - 1
+ || memcmp (buf, "abcdefgh\n", 9))
+ FAIL ();
+- if (pread64 (fileno (stdin), buf, l0 + sizeof (buf) - 1, sizeof (buf) - 3)
+- != sizeof (buf) - 1
++ if (pread64 (fileno (stdin), buf, l0 + buf_size - 1, buf_size - 3)
++ != buf_size - 1
+ || memcmp (buf, "h\nABCDEFG", 9))
+ FAIL ();
+
+ #if __USE_FORTIFY_LEVEL >= 1
+ CHK_FAIL_START
+- if (pread64 (fileno (stdin), buf, sizeof (buf) + 1, 2 * sizeof (buf))
+- != sizeof (buf) + 1)
++ if (pread64 (fileno (stdin), buf, buf_size + 1, 2 * buf_size)
++ != buf_size + 1)
+ FAIL ();
+ CHK_FAIL_END
+
+ CHK_FAIL_START
+- if (pread64 (fileno (stdin), buf, l0 + sizeof (buf) + 1, 2 * sizeof (buf))
+- != sizeof (buf) + 1)
++ if (pread64 (fileno (stdin), buf, l0 + buf_size + 1, 2 * buf_size)
++ != buf_size + 1)
+ FAIL ();
+ CHK_FAIL_END
+ #endif
+@@ -1179,7 +1189,7 @@ do_test (void)
+ CHK_FAIL2_END
+
+ CHK_FAIL2_START
+- snprintf (buf, sizeof (buf), "%3$d\n", 1, 2, 3, 4);
++ snprintf (buf, buf_size, "%3$d\n", 1, 2, 3, 4);
+ CHK_FAIL2_END
+
+ int sp[2];
+diff --git a/debug/tst-chk7.c b/debug/tst-chk7.c
+new file mode 100644
+index 0000000000000000..2a7b32381268135c
+--- /dev/null
++++ b/debug/tst-chk7.c
+@@ -0,0 +1,2 @@
++#define _FORTIFY_SOURCE 3
++#include "tst-chk1.c"
+diff --git a/debug/tst-chk8.cc b/debug/tst-chk8.cc
+new file mode 100644
+index 0000000000000000..2a7b32381268135c
+--- /dev/null
++++ b/debug/tst-chk8.cc
+@@ -0,0 +1,2 @@
++#define _FORTIFY_SOURCE 3
++#include "tst-chk1.c"
diff --git a/glibc-rh2033684-9.patch b/glibc-rh2033684-9.patch
new file mode 100644
index 0000000000000000000000000000000000000000..467ece4493b766bc27c7c0a33814d69e9cfb65e9
--- /dev/null
+++ b/glibc-rh2033684-9.patch
@@ -0,0 +1,23 @@
+commit ae23fa3e5fe24daf94fc7f8e5268bb8ceeda7477
+Author: Siddhesh Poyarekar
+Date: Thu Dec 16 07:19:14 2021 +0530
+
+ __glibc_unsafe_len: Fix comment
+
+ We know that the length is *unsafe*.
+
+ Signed-off-by: Siddhesh Poyarekar
+
+diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
+index 17b84a2e6c69d961..147339957c4ad490 100644
+--- a/misc/sys/cdefs.h
++++ b/misc/sys/cdefs.h
+@@ -150,7 +150,7 @@
+ __s, __osz)) \
+ && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz))
+
+-/* Conversely, we know at compile time that the length is safe if the
++/* Conversely, we know at compile time that the length is unsafe if the
+ __L * __S <= __OBJSZ condition can be folded to a constant and if it is
+ false. */
+ #define __glibc_unsafe_len(__l, __s, __osz) \
diff --git a/glibc-rh2037416-1.patch b/glibc-rh2037416-1.patch
new file mode 100644
index 0000000000000000000000000000000000000000..3fddefec5c038b3a3ec6c4c31d2f3e3c2141cf40
--- /dev/null
+++ b/glibc-rh2037416-1.patch
@@ -0,0 +1,136 @@
+From 07b427296b8d59f439144029d9a948f6c1ce0a31 Mon Sep 17 00:00:00 2001
+From: Wilco Dijkstra
+Date: Tue, 10 Aug 2021 13:30:27 +0100
+Subject: [PATCH] [1/5] AArch64: Improve A64FX memset for small sizes
+
+Improve performance of small memsets by reducing instruction counts and
+improving code alignment. Bench-memset shows 35-45% performance gain for
+small sizes.
+
+Reviewed-by: Naohiro Tamura
+---
+ sysdeps/aarch64/multiarch/memset_a64fx.S | 96 +++++++++---------------
+ 1 file changed, 36 insertions(+), 60 deletions(-)
+
+diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S
+index ce54e5418b..cf3d402ef6 100644
+--- a/sysdeps/aarch64/multiarch/memset_a64fx.S
++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S
+@@ -51,78 +51,54 @@
+ .endm
+
+ .macro st1b_unroll first=0, last=7
+- st1b z0.b, p0, [dst, #\first, mul vl]
++ st1b z0.b, p0, [dst, \first, mul vl]
+ .if \last-\first
+ st1b_unroll "(\first+1)", \last
+ .endif
+ .endm
+
+- .macro shortcut_for_small_size exit
+- // if rest <= vector_length * 2
+- whilelo p0.b, xzr, count
+- whilelo p1.b, vector_length, count
+- b.last 1f
+- st1b z0.b, p0, [dstin, #0, mul vl]
+- st1b z0.b, p1, [dstin, #1, mul vl]
+- ret
+-1: // if rest > vector_length * 8
+- cmp count, vector_length, lsl 3 // vector_length * 8
+- b.hi \exit
+- // if rest <= vector_length * 4
+- lsl tmp1, vector_length, 1 // vector_length * 2
+- whilelo p2.b, tmp1, count
+- incb tmp1
+- whilelo p3.b, tmp1, count
+- b.last 1f
+- st1b z0.b, p0, [dstin, #0, mul vl]
+- st1b z0.b, p1, [dstin, #1, mul vl]
+- st1b z0.b, p2, [dstin, #2, mul vl]
+- st1b z0.b, p3, [dstin, #3, mul vl]
+- ret
+-1: // if rest <= vector_length * 8
+- lsl tmp1, vector_length, 2 // vector_length * 4
+- whilelo p4.b, tmp1, count
+- incb tmp1
+- whilelo p5.b, tmp1, count
+- b.last 1f
+- st1b z0.b, p0, [dstin, #0, mul vl]
+- st1b z0.b, p1, [dstin, #1, mul vl]
+- st1b z0.b, p2, [dstin, #2, mul vl]
+- st1b z0.b, p3, [dstin, #3, mul vl]
+- st1b z0.b, p4, [dstin, #4, mul vl]
+- st1b z0.b, p5, [dstin, #5, mul vl]
+- ret
+-1: lsl tmp1, vector_length, 2 // vector_length * 4
+- incb tmp1 // vector_length * 5
+- incb tmp1 // vector_length * 6
+- whilelo p6.b, tmp1, count
+- incb tmp1
+- whilelo p7.b, tmp1, count
+- st1b z0.b, p0, [dstin, #0, mul vl]
+- st1b z0.b, p1, [dstin, #1, mul vl]
+- st1b z0.b, p2, [dstin, #2, mul vl]
+- st1b z0.b, p3, [dstin, #3, mul vl]
+- st1b z0.b, p4, [dstin, #4, mul vl]
+- st1b z0.b, p5, [dstin, #5, mul vl]
+- st1b z0.b, p6, [dstin, #6, mul vl]
+- st1b z0.b, p7, [dstin, #7, mul vl]
+- ret
+- .endm
+
+-ENTRY (MEMSET)
++#undef BTI_C
++#define BTI_C
+
++ENTRY (MEMSET)
+ PTR_ARG (0)
+ SIZE_ARG (2)
+
+- cbnz count, 1f
+- ret
+-1: dup z0.b, valw
+ cntb vector_length
+- // shortcut for less than vector_length * 8
+- // gives a free ptrue to p0.b for n >= vector_length
+- shortcut_for_small_size L(vl_agnostic)
+- // end of shortcut
++ dup z0.b, valw
++ whilelo p0.b, vector_length, count
++ b.last 1f
++ whilelo p1.b, xzr, count
++ st1b z0.b, p1, [dstin, 0, mul vl]
++ st1b z0.b, p0, [dstin, 1, mul vl]
++ ret
++
++ // count >= vector_length * 2
++1: cmp count, vector_length, lsl 2
++ add dstend, dstin, count
++ b.hi 1f
++ st1b z0.b, p0, [dstin, 0, mul vl]
++ st1b z0.b, p0, [dstin, 1, mul vl]
++ st1b z0.b, p0, [dstend, -2, mul vl]
++ st1b z0.b, p0, [dstend, -1, mul vl]
++ ret
++
++ // count > vector_length * 4
++1: lsl tmp1, vector_length, 3
++ cmp count, tmp1
++ b.hi L(vl_agnostic)
++ st1b z0.b, p0, [dstin, 0, mul vl]
++ st1b z0.b, p0, [dstin, 1, mul vl]
++ st1b z0.b, p0, [dstin, 2, mul vl]
++ st1b z0.b, p0, [dstin, 3, mul vl]
++ st1b z0.b, p0, [dstend, -4, mul vl]
++ st1b z0.b, p0, [dstend, -3, mul vl]
++ st1b z0.b, p0, [dstend, -2, mul vl]
++ st1b z0.b, p0, [dstend, -1, mul vl]
++ ret
+
++ .p2align 4
+ L(vl_agnostic): // VL Agnostic
+ mov rest, count
+ mov dst, dstin
+--
+2.31.1
+
diff --git a/glibc-rh2037416-2.patch b/glibc-rh2037416-2.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e991e91964ce152e4dbd43cd07ab4ab0d136d616
--- /dev/null
+++ b/glibc-rh2037416-2.patch
@@ -0,0 +1,131 @@
+From 9bc2ed8f46d80859a5596789cc9e8cc2de84b0e7 Mon Sep 17 00:00:00 2001
+From: Wilco Dijkstra
+Date: Tue, 10 Aug 2021 13:39:37 +0100
+Subject: [PATCH] [2/5] AArch64: Improve A64FX memset for large sizes
+
+Improve performance of large memsets. Simplify alignment code. For zero memset
+use DC ZVA, which almost doubles performance. For non-zero memsets use the
+unroll8 loop which is about 10% faster.
+
+Reviewed-by: Naohiro Tamura
+---
+ sysdeps/aarch64/multiarch/memset_a64fx.S | 85 +++++++-----------------
+ 1 file changed, 25 insertions(+), 60 deletions(-)
+
+diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S
+index cf3d402ef6..75cf43ae79 100644
+--- a/sysdeps/aarch64/multiarch/memset_a64fx.S
++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S
+@@ -27,14 +27,11 @@
+ */
+
+ #define L1_SIZE (64*1024) // L1 64KB
+-#define L2_SIZE (8*1024*1024) // L2 8MB - 1MB
++#define L2_SIZE (8*1024*1024) // L2 8MB
+ #define CACHE_LINE_SIZE 256
+ #define PF_DIST_L1 (CACHE_LINE_SIZE * 16) // Prefetch distance L1
+-#define ZF_DIST (CACHE_LINE_SIZE * 21) // Zerofill distance
+-#define rest x8
++#define rest x2
+ #define vector_length x9
+-#define vl_remainder x10 // vector_length remainder
+-#define cl_remainder x11 // CACHE_LINE_SIZE remainder
+
+ #if HAVE_AARCH64_SVE_ASM
+ # if IS_IN (libc)
+@@ -42,14 +39,6 @@
+
+ .arch armv8.2-a+sve
+
+- .macro dc_zva times
+- dc zva, tmp1
+- add tmp1, tmp1, CACHE_LINE_SIZE
+- .if \times-1
+- dc_zva "(\times-1)"
+- .endif
+- .endm
+-
+ .macro st1b_unroll first=0, last=7
+ st1b z0.b, p0, [dst, \first, mul vl]
+ .if \last-\first
+@@ -188,54 +177,30 @@ L(L1_prefetch): // if rest >= L1_SIZE
+ cbnz rest, L(unroll32)
+ ret
+
+-L(L2):
+- // align dst address at vector_length byte boundary
+- sub tmp1, vector_length, 1
+- ands tmp2, dst, tmp1
+- // if vl_remainder == 0
+- b.eq 1f
+- sub vl_remainder, vector_length, tmp2
+- // process remainder until the first vector_length boundary
+- whilelt p2.b, xzr, vl_remainder
+- st1b z0.b, p2, [dst]
+- add dst, dst, vl_remainder
+- sub rest, rest, vl_remainder
+- // align dstin address at CACHE_LINE_SIZE byte boundary
+-1: mov tmp1, CACHE_LINE_SIZE
+- ands tmp2, dst, CACHE_LINE_SIZE - 1
+- // if cl_remainder == 0
+- b.eq L(L2_dc_zva)
+- sub cl_remainder, tmp1, tmp2
+- // process remainder until the first CACHE_LINE_SIZE boundary
+- mov tmp1, xzr // index
+-2: whilelt p2.b, tmp1, cl_remainder
+- st1b z0.b, p2, [dst, tmp1]
+- incb tmp1
+- cmp tmp1, cl_remainder
+- b.lo 2b
+- add dst, dst, cl_remainder
+- sub rest, rest, cl_remainder
+-
+-L(L2_dc_zva):
+- // zero fill
+- mov tmp1, dst
+- dc_zva (ZF_DIST / CACHE_LINE_SIZE) - 1
+- mov zva_len, ZF_DIST
+- add tmp1, zva_len, CACHE_LINE_SIZE * 2
+- // unroll
++ // count >= L2_SIZE
+ .p2align 3
+-1: st1b_unroll 0, 3
+- add tmp2, dst, zva_len
+- dc zva, tmp2
+- st1b_unroll 4, 7
+- add tmp2, tmp2, CACHE_LINE_SIZE
+- dc zva, tmp2
+- add dst, dst, CACHE_LINE_SIZE * 2
+- sub rest, rest, CACHE_LINE_SIZE * 2
+- cmp rest, tmp1 // ZF_DIST + CACHE_LINE_SIZE * 2
+- b.ge 1b
+- cbnz rest, L(unroll8)
+- ret
++L(L2):
++ tst valw, 255
++ b.ne L(unroll8)
++ // align dst to CACHE_LINE_SIZE byte boundary
++ and tmp2, dst, CACHE_LINE_SIZE - 1
++ st1b z0.b, p0, [dst, 0, mul vl]
++ st1b z0.b, p0, [dst, 1, mul vl]
++ st1b z0.b, p0, [dst, 2, mul vl]
++ st1b z0.b, p0, [dst, 3, mul vl]
++ sub dst, dst, tmp2
++ add count, count, tmp2
++
++ // clear cachelines using DC ZVA
++ sub count, count, CACHE_LINE_SIZE * 2
++ .p2align 4
++1: add dst, dst, CACHE_LINE_SIZE
++ dc zva, dst
++ subs count, count, CACHE_LINE_SIZE
++ b.hi 1b
++ add count, count, CACHE_LINE_SIZE
++ add dst, dst, CACHE_LINE_SIZE
++ b L(last)
+
+ END (MEMSET)
+ libc_hidden_builtin_def (MEMSET)
+--
+2.31.1
+
diff --git a/glibc-rh2037416-3.patch b/glibc-rh2037416-3.patch
new file mode 100644
index 0000000000000000000000000000000000000000..3ac7aa2f437a0d191c9ad562d7467de2cd9097e9
--- /dev/null
+++ b/glibc-rh2037416-3.patch
@@ -0,0 +1,80 @@
+From 186092c6ba8825598ffdbf15dbf0823c771f560d Mon Sep 17 00:00:00 2001
+From: Wilco Dijkstra
+Date: Tue, 10 Aug 2021 13:42:07 +0100
+Subject: [PATCH] [3/5] AArch64: Improve A64FX memset for remaining bytes
+
+Simplify handling of remaining bytes. Avoid lots of taken branches and complex
+whilelo computations, instead unconditionally write vectors from the end.
+
+Reviewed-by: Naohiro Tamura
+---
+ sysdeps/aarch64/multiarch/memset_a64fx.S | 46 +++++++-----------------
+ 1 file changed, 13 insertions(+), 33 deletions(-)
+
+diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S
+index 75cf43ae79..337c86be6f 100644
+--- a/sysdeps/aarch64/multiarch/memset_a64fx.S
++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S
+@@ -130,38 +130,19 @@ L(unroll8):
+ b 1b
+
+ L(last):
+- whilelo p0.b, xzr, rest
+- whilelo p1.b, vector_length, rest
+- b.last 1f
+- st1b z0.b, p0, [dst, #0, mul vl]
+- st1b z0.b, p1, [dst, #1, mul vl]
+- ret
+-1: lsl tmp1, vector_length, 1 // vector_length * 2
+- whilelo p2.b, tmp1, rest
+- incb tmp1
+- whilelo p3.b, tmp1, rest
+- b.last 1f
+- st1b z0.b, p0, [dst, #0, mul vl]
+- st1b z0.b, p1, [dst, #1, mul vl]
+- st1b z0.b, p2, [dst, #2, mul vl]
+- st1b z0.b, p3, [dst, #3, mul vl]
+- ret
+-1: lsl tmp1, vector_length, 2 // vector_length * 4
+- whilelo p4.b, tmp1, rest
+- incb tmp1
+- whilelo p5.b, tmp1, rest
+- incb tmp1
+- whilelo p6.b, tmp1, rest
+- incb tmp1
+- whilelo p7.b, tmp1, rest
+- st1b z0.b, p0, [dst, #0, mul vl]
+- st1b z0.b, p1, [dst, #1, mul vl]
+- st1b z0.b, p2, [dst, #2, mul vl]
+- st1b z0.b, p3, [dst, #3, mul vl]
+- st1b z0.b, p4, [dst, #4, mul vl]
+- st1b z0.b, p5, [dst, #5, mul vl]
+- st1b z0.b, p6, [dst, #6, mul vl]
+- st1b z0.b, p7, [dst, #7, mul vl]
++ cmp count, vector_length, lsl 1
++ b.ls 2f
++ add tmp2, vector_length, vector_length, lsl 2
++ cmp count, tmp2
++ b.ls 5f
++ st1b z0.b, p0, [dstend, -8, mul vl]
++ st1b z0.b, p0, [dstend, -7, mul vl]
++ st1b z0.b, p0, [dstend, -6, mul vl]
++5: st1b z0.b, p0, [dstend, -5, mul vl]
++ st1b z0.b, p0, [dstend, -4, mul vl]
++ st1b z0.b, p0, [dstend, -3, mul vl]
++2: st1b z0.b, p0, [dstend, -2, mul vl]
++ st1b z0.b, p0, [dstend, -1, mul vl]
+ ret
+
+ L(L1_prefetch): // if rest >= L1_SIZE
+@@ -199,7 +180,6 @@ L(L2):
+ subs count, count, CACHE_LINE_SIZE
+ b.hi 1b
+ add count, count, CACHE_LINE_SIZE
+- add dst, dst, CACHE_LINE_SIZE
+ b L(last)
+
+ END (MEMSET)
+--
+2.31.1
+
diff --git a/glibc-rh2037416-4.patch b/glibc-rh2037416-4.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e057eebaa2d1b55ef624488ecc94e143b1d52a0f
--- /dev/null
+++ b/glibc-rh2037416-4.patch
@@ -0,0 +1,51 @@
+From e69d9981f858a38e19304e6ff5ebdf89f2cb0ba0 Mon Sep 17 00:00:00 2001
+From: Wilco Dijkstra
+Date: Tue, 10 Aug 2021 13:44:27 +0100
+Subject: [PATCH] [4/5] AArch64: Improve A64FX memset by removing unroll32
+
+Remove unroll32 code since it doesn't improve performance.
+
+Reviewed-by: Naohiro Tamura
+---
+ sysdeps/aarch64/multiarch/memset_a64fx.S | 18 +-----------------
+ 1 file changed, 1 insertion(+), 17 deletions(-)
+
+diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S
+index 337c86be6f..ef0315658a 100644
+--- a/sysdeps/aarch64/multiarch/memset_a64fx.S
++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S
+@@ -102,22 +102,6 @@ L(vl_agnostic): // VL Agnostic
+ ccmp vector_length, tmp1, 0, cs
+ b.eq L(L1_prefetch)
+
+-L(unroll32):
+- lsl tmp1, vector_length, 3 // vector_length * 8
+- lsl tmp2, vector_length, 5 // vector_length * 32
+- .p2align 3
+-1: cmp rest, tmp2
+- b.cc L(unroll8)
+- st1b_unroll
+- add dst, dst, tmp1
+- st1b_unroll
+- add dst, dst, tmp1
+- st1b_unroll
+- add dst, dst, tmp1
+- st1b_unroll
+- add dst, dst, tmp1
+- sub rest, rest, tmp2
+- b 1b
+
+ L(unroll8):
+ lsl tmp1, vector_length, 3
+@@ -155,7 +139,7 @@ L(L1_prefetch): // if rest >= L1_SIZE
+ sub rest, rest, CACHE_LINE_SIZE * 2
+ cmp rest, L1_SIZE
+ b.ge 1b
+- cbnz rest, L(unroll32)
++ cbnz rest, L(unroll8)
+ ret
+
+ // count >= L2_SIZE
+--
+2.31.1
+
diff --git a/glibc-rh2037416-5.patch b/glibc-rh2037416-5.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c92c2cf21376b348bb4f03fcd6325ef5745db940
--- /dev/null
+++ b/glibc-rh2037416-5.patch
@@ -0,0 +1,96 @@
+From a5db6a5cae6a92d1675c013e5c8d972768721576 Mon Sep 17 00:00:00 2001
+From: Wilco Dijkstra
+Date: Tue, 10 Aug 2021 13:46:20 +0100
+Subject: [PATCH] [5/5] AArch64: Improve A64FX memset medium loops
+
+Simplify the code for memsets smaller than L1. Improve the unroll8 and
+L1_prefetch loops.
+
+Reviewed-by: Naohiro Tamura
+---
+ sysdeps/aarch64/multiarch/memset_a64fx.S | 45 ++++++++++--------------
+ 1 file changed, 19 insertions(+), 26 deletions(-)
+
+diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S
+index ef0315658a..7bf759b6a7 100644
+--- a/sysdeps/aarch64/multiarch/memset_a64fx.S
++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S
+@@ -30,7 +30,6 @@
+ #define L2_SIZE (8*1024*1024) // L2 8MB
+ #define CACHE_LINE_SIZE 256
+ #define PF_DIST_L1 (CACHE_LINE_SIZE * 16) // Prefetch distance L1
+-#define rest x2
+ #define vector_length x9
+
+ #if HAVE_AARCH64_SVE_ASM
+@@ -89,29 +88,19 @@ ENTRY (MEMSET)
+
+ .p2align 4
+ L(vl_agnostic): // VL Agnostic
+- mov rest, count
+ mov dst, dstin
+- add dstend, dstin, count
+- // if rest >= L2_SIZE && vector_length == 64 then L(L2)
+- mov tmp1, 64
+- cmp rest, L2_SIZE
+- ccmp vector_length, tmp1, 0, cs
+- b.eq L(L2)
+- // if rest >= L1_SIZE && vector_length == 64 then L(L1_prefetch)
+- cmp rest, L1_SIZE
+- ccmp vector_length, tmp1, 0, cs
+- b.eq L(L1_prefetch)
+-
++ cmp count, L1_SIZE
++ b.hi L(L1_prefetch)
+
++ // count >= 8 * vector_length
+ L(unroll8):
+- lsl tmp1, vector_length, 3
+- .p2align 3
+-1: cmp rest, tmp1
+- b.cc L(last)
+- st1b_unroll
++ sub count, count, tmp1
++ .p2align 4
++1: st1b_unroll 0, 7
+ add dst, dst, tmp1
+- sub rest, rest, tmp1
+- b 1b
++ subs count, count, tmp1
++ b.hi 1b
++ add count, count, tmp1
+
+ L(last):
+ cmp count, vector_length, lsl 1
+@@ -129,18 +118,22 @@ L(last):
+ st1b z0.b, p0, [dstend, -1, mul vl]
+ ret
+
+-L(L1_prefetch): // if rest >= L1_SIZE
++ // count >= L1_SIZE
+ .p2align 3
++L(L1_prefetch):
++ cmp count, L2_SIZE
++ b.hs L(L2)
++ cmp vector_length, 64
++ b.ne L(unroll8)
+ 1: st1b_unroll 0, 3
+ prfm pstl1keep, [dst, PF_DIST_L1]
+ st1b_unroll 4, 7
+ prfm pstl1keep, [dst, PF_DIST_L1 + CACHE_LINE_SIZE]
+ add dst, dst, CACHE_LINE_SIZE * 2
+- sub rest, rest, CACHE_LINE_SIZE * 2
+- cmp rest, L1_SIZE
+- b.ge 1b
+- cbnz rest, L(unroll8)
+- ret
++ sub count, count, CACHE_LINE_SIZE * 2
++ cmp count, PF_DIST_L1
++ b.hs 1b
++ b L(unroll8)
+
+ // count >= L2_SIZE
+ .p2align 3
+--
+2.31.1
+
diff --git a/glibc-rh2037416-6.patch b/glibc-rh2037416-6.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b2522ad2367ddedb5d803da018ecf53ecfae5709
--- /dev/null
+++ b/glibc-rh2037416-6.patch
@@ -0,0 +1,39 @@
+From 1d9f99ce1b3788d1897cb53a76d57e973111b8fe Mon Sep 17 00:00:00 2001
+From: Naohiro Tamura
+Date: Fri, 27 Aug 2021 05:03:04 +0000
+Subject: [PATCH] AArch64: Update A64FX memset not to degrade at 16KB
+
+This patch updates unroll8 code so as not to degrade at the peak
+performance 16KB for both FX1000 and FX700.
+
+Inserted 2 instructions at the beginning of the unroll8 loop,
+cmp and branch, are a workaround that is found heuristically.
+
+Reviewed-by: Wilco Dijkstra
+---
+ sysdeps/aarch64/multiarch/memset_a64fx.S | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S
+index 7bf759b6a7..f7dfdaace7 100644
+--- a/sysdeps/aarch64/multiarch/memset_a64fx.S
++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S
+@@ -96,7 +96,14 @@ L(vl_agnostic): // VL Agnostic
+ L(unroll8):
+ sub count, count, tmp1
+ .p2align 4
+-1: st1b_unroll 0, 7
++ // The 2 instructions at the beginning of the following loop,
++ // cmp and branch, are a workaround so as not to degrade at
++ // the peak performance 16KB.
++ // It is found heuristically and the branch condition, b.ne,
++ // is chosen intentionally never to jump.
++1: cmp xzr, xzr
++ b.ne 1b
++ st1b_unroll 0, 7
+ add dst, dst, tmp1
+ subs count, count, tmp1
+ b.hi 1b
+--
+2.31.1
+
diff --git a/glibc-rh2037416-7.patch b/glibc-rh2037416-7.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e57fef7079eeb6fdf327d1d9acb2b02201329948
--- /dev/null
+++ b/glibc-rh2037416-7.patch
@@ -0,0 +1,32 @@
+From 381b29616abb82babc8163bdf516c6da87544b35 Mon Sep 17 00:00:00 2001
+From: Naohiro Tamura
+Date: Fri, 24 Sep 2021 07:49:59 +0000
+Subject: [PATCH] aarch64: Disable A64FX memcpy/memmove BTI unconditionally
+
+This patch disables A64FX memcpy/memmove BTI instruction insertion
+unconditionally such as A64FX memset patch [1] for performance.
+
+[1] commit 07b427296b8d59f439144029d9a948f6c1ce0a31
+
+Reviewed-by: Szabolcs Nagy
+---
+ sysdeps/aarch64/multiarch/memcpy_a64fx.S | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/sysdeps/aarch64/multiarch/memcpy_a64fx.S b/sysdeps/aarch64/multiarch/memcpy_a64fx.S
+index 65528405bb..ae7464e09f 100644
+--- a/sysdeps/aarch64/multiarch/memcpy_a64fx.S
++++ b/sysdeps/aarch64/multiarch/memcpy_a64fx.S
+@@ -19,6 +19,9 @@
+
+ #include
+
++#undef BTI_C
++#define BTI_C
++
+ /* Assumptions:
+ *
+ * ARMv8.2-a, AArch64, unaligned accesses, sve
+--
+2.31.1
+
diff --git a/glibc-rh2037416-8.patch b/glibc-rh2037416-8.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6a6833254eb915ac2fa595cfc29035f89664b4d7
--- /dev/null
+++ b/glibc-rh2037416-8.patch
@@ -0,0 +1,630 @@
+From b31bd11454fade731e5158b1aea40b133ae19926 Mon Sep 17 00:00:00 2001
+From: Wilco Dijkstra
+Date: Thu, 2 Dec 2021 18:33:26 +0000
+Subject: [PATCH] AArch64: Improve A64FX memcpy
+
+v2 is a complete rewrite of the A64FX memcpy. Performance is improved
+by streamlining the code, aligning all large copies and using a single
+unrolled loop for all sizes. The code size for memcpy and memmove goes
+down from 1796 bytes to 868 bytes. Performance is better in all cases:
+bench-memcpy-random is 2.3% faster overall, bench-memcpy-large is ~33%
+faster for large sizes, bench-memcpy-walk is 25% faster for small sizes
+and 20% for the largest sizes. The geomean of all tests in bench-memcpy
+is 5.1% faster, and total time is reduced by 4%.
+
+Reviewed-by: Szabolcs Nagy
+---
+ sysdeps/aarch64/multiarch/memcpy_a64fx.S | 546 ++++++++++-------------
+ 1 file changed, 225 insertions(+), 321 deletions(-)
+
+diff --git a/sysdeps/aarch64/multiarch/memcpy_a64fx.S b/sysdeps/aarch64/multiarch/memcpy_a64fx.S
+index ae7464e09f..0b306925e6 100644
+--- a/sysdeps/aarch64/multiarch/memcpy_a64fx.S
++++ b/sysdeps/aarch64/multiarch/memcpy_a64fx.S
+@@ -28,20 +28,15 @@
+ *
+ */
+
+-#define L2_SIZE (8*1024*1024)/2 // L2 8MB/2
+-#define CACHE_LINE_SIZE 256
+-#define ZF_DIST (CACHE_LINE_SIZE * 21) // Zerofill distance
+-#define dest x0
+-#define src x1
+-#define n x2 // size
+-#define tmp1 x3
+-#define tmp2 x4
+-#define tmp3 x5
+-#define rest x6
+-#define dest_ptr x7
+-#define src_ptr x8
+-#define vector_length x9
+-#define cl_remainder x10 // CACHE_LINE_SIZE remainder
++#define dstin x0
++#define src x1
++#define n x2
++#define dst x3
++#define dstend x4
++#define srcend x5
++#define tmp x6
++#define vlen x7
++#define vlen8 x8
+
+ #if HAVE_AARCH64_SVE_ASM
+ # if IS_IN (libc)
+@@ -50,45 +45,37 @@
+
+ .arch armv8.2-a+sve
+
+- .macro dc_zva times
+- dc zva, tmp1
+- add tmp1, tmp1, CACHE_LINE_SIZE
+- .if \times-1
+- dc_zva "(\times-1)"
+- .endif
+- .endm
+-
+ .macro ld1b_unroll8
+- ld1b z0.b, p0/z, [src_ptr, #0, mul vl]
+- ld1b z1.b, p0/z, [src_ptr, #1, mul vl]
+- ld1b z2.b, p0/z, [src_ptr, #2, mul vl]
+- ld1b z3.b, p0/z, [src_ptr, #3, mul vl]
+- ld1b z4.b, p0/z, [src_ptr, #4, mul vl]
+- ld1b z5.b, p0/z, [src_ptr, #5, mul vl]
+- ld1b z6.b, p0/z, [src_ptr, #6, mul vl]
+- ld1b z7.b, p0/z, [src_ptr, #7, mul vl]
++ ld1b z0.b, p0/z, [src, 0, mul vl]
++ ld1b z1.b, p0/z, [src, 1, mul vl]
++ ld1b z2.b, p0/z, [src, 2, mul vl]
++ ld1b z3.b, p0/z, [src, 3, mul vl]
++ ld1b z4.b, p0/z, [src, 4, mul vl]
++ ld1b z5.b, p0/z, [src, 5, mul vl]
++ ld1b z6.b, p0/z, [src, 6, mul vl]
++ ld1b z7.b, p0/z, [src, 7, mul vl]
+ .endm
+
+ .macro stld1b_unroll4a
+- st1b z0.b, p0, [dest_ptr, #0, mul vl]
+- st1b z1.b, p0, [dest_ptr, #1, mul vl]
+- ld1b z0.b, p0/z, [src_ptr, #0, mul vl]
+- ld1b z1.b, p0/z, [src_ptr, #1, mul vl]
+- st1b z2.b, p0, [dest_ptr, #2, mul vl]
+- st1b z3.b, p0, [dest_ptr, #3, mul vl]
+- ld1b z2.b, p0/z, [src_ptr, #2, mul vl]
+- ld1b z3.b, p0/z, [src_ptr, #3, mul vl]
++ st1b z0.b, p0, [dst, 0, mul vl]
++ st1b z1.b, p0, [dst, 1, mul vl]
++ ld1b z0.b, p0/z, [src, 0, mul vl]
++ ld1b z1.b, p0/z, [src, 1, mul vl]
++ st1b z2.b, p0, [dst, 2, mul vl]
++ st1b z3.b, p0, [dst, 3, mul vl]
++ ld1b z2.b, p0/z, [src, 2, mul vl]
++ ld1b z3.b, p0/z, [src, 3, mul vl]
+ .endm
+
+ .macro stld1b_unroll4b
+- st1b z4.b, p0, [dest_ptr, #4, mul vl]
+- st1b z5.b, p0, [dest_ptr, #5, mul vl]
+- ld1b z4.b, p0/z, [src_ptr, #4, mul vl]
+- ld1b z5.b, p0/z, [src_ptr, #5, mul vl]
+- st1b z6.b, p0, [dest_ptr, #6, mul vl]
+- st1b z7.b, p0, [dest_ptr, #7, mul vl]
+- ld1b z6.b, p0/z, [src_ptr, #6, mul vl]
+- ld1b z7.b, p0/z, [src_ptr, #7, mul vl]
++ st1b z4.b, p0, [dst, 4, mul vl]
++ st1b z5.b, p0, [dst, 5, mul vl]
++ ld1b z4.b, p0/z, [src, 4, mul vl]
++ ld1b z5.b, p0/z, [src, 5, mul vl]
++ st1b z6.b, p0, [dst, 6, mul vl]
++ st1b z7.b, p0, [dst, 7, mul vl]
++ ld1b z6.b, p0/z, [src, 6, mul vl]
++ ld1b z7.b, p0/z, [src, 7, mul vl]
+ .endm
+
+ .macro stld1b_unroll8
+@@ -97,87 +84,18 @@
+ .endm
+
+ .macro st1b_unroll8
+- st1b z0.b, p0, [dest_ptr, #0, mul vl]
+- st1b z1.b, p0, [dest_ptr, #1, mul vl]
+- st1b z2.b, p0, [dest_ptr, #2, mul vl]
+- st1b z3.b, p0, [dest_ptr, #3, mul vl]
+- st1b z4.b, p0, [dest_ptr, #4, mul vl]
+- st1b z5.b, p0, [dest_ptr, #5, mul vl]
+- st1b z6.b, p0, [dest_ptr, #6, mul vl]
+- st1b z7.b, p0, [dest_ptr, #7, mul vl]
++ st1b z0.b, p0, [dst, 0, mul vl]
++ st1b z1.b, p0, [dst, 1, mul vl]
++ st1b z2.b, p0, [dst, 2, mul vl]
++ st1b z3.b, p0, [dst, 3, mul vl]
++ st1b z4.b, p0, [dst, 4, mul vl]
++ st1b z5.b, p0, [dst, 5, mul vl]
++ st1b z6.b, p0, [dst, 6, mul vl]
++ st1b z7.b, p0, [dst, 7, mul vl]
+ .endm
+
+- .macro shortcut_for_small_size exit
+- // if rest <= vector_length * 2
+- whilelo p0.b, xzr, n
+- whilelo p1.b, vector_length, n
+- b.last 1f
+- ld1b z0.b, p0/z, [src, #0, mul vl]
+- ld1b z1.b, p1/z, [src, #1, mul vl]
+- st1b z0.b, p0, [dest, #0, mul vl]
+- st1b z1.b, p1, [dest, #1, mul vl]
+- ret
+-1: // if rest > vector_length * 8
+- cmp n, vector_length, lsl 3 // vector_length * 8
+- b.hi \exit
+- // if rest <= vector_length * 4
+- lsl tmp1, vector_length, 1 // vector_length * 2
+- whilelo p2.b, tmp1, n
+- incb tmp1
+- whilelo p3.b, tmp1, n
+- b.last 1f
+- ld1b z0.b, p0/z, [src, #0, mul vl]
+- ld1b z1.b, p1/z, [src, #1, mul vl]
+- ld1b z2.b, p2/z, [src, #2, mul vl]
+- ld1b z3.b, p3/z, [src, #3, mul vl]
+- st1b z0.b, p0, [dest, #0, mul vl]
+- st1b z1.b, p1, [dest, #1, mul vl]
+- st1b z2.b, p2, [dest, #2, mul vl]
+- st1b z3.b, p3, [dest, #3, mul vl]
+- ret
+-1: // if rest <= vector_length * 8
+- lsl tmp1, vector_length, 2 // vector_length * 4
+- whilelo p4.b, tmp1, n
+- incb tmp1
+- whilelo p5.b, tmp1, n
+- b.last 1f
+- ld1b z0.b, p0/z, [src, #0, mul vl]
+- ld1b z1.b, p1/z, [src, #1, mul vl]
+- ld1b z2.b, p2/z, [src, #2, mul vl]
+- ld1b z3.b, p3/z, [src, #3, mul vl]
+- ld1b z4.b, p4/z, [src, #4, mul vl]
+- ld1b z5.b, p5/z, [src, #5, mul vl]
+- st1b z0.b, p0, [dest, #0, mul vl]
+- st1b z1.b, p1, [dest, #1, mul vl]
+- st1b z2.b, p2, [dest, #2, mul vl]
+- st1b z3.b, p3, [dest, #3, mul vl]
+- st1b z4.b, p4, [dest, #4, mul vl]
+- st1b z5.b, p5, [dest, #5, mul vl]
+- ret
+-1: lsl tmp1, vector_length, 2 // vector_length * 4
+- incb tmp1 // vector_length * 5
+- incb tmp1 // vector_length * 6
+- whilelo p6.b, tmp1, n
+- incb tmp1
+- whilelo p7.b, tmp1, n
+- ld1b z0.b, p0/z, [src, #0, mul vl]
+- ld1b z1.b, p1/z, [src, #1, mul vl]
+- ld1b z2.b, p2/z, [src, #2, mul vl]
+- ld1b z3.b, p3/z, [src, #3, mul vl]
+- ld1b z4.b, p4/z, [src, #4, mul vl]
+- ld1b z5.b, p5/z, [src, #5, mul vl]
+- ld1b z6.b, p6/z, [src, #6, mul vl]
+- ld1b z7.b, p7/z, [src, #7, mul vl]
+- st1b z0.b, p0, [dest, #0, mul vl]
+- st1b z1.b, p1, [dest, #1, mul vl]
+- st1b z2.b, p2, [dest, #2, mul vl]
+- st1b z3.b, p3, [dest, #3, mul vl]
+- st1b z4.b, p4, [dest, #4, mul vl]
+- st1b z5.b, p5, [dest, #5, mul vl]
+- st1b z6.b, p6, [dest, #6, mul vl]
+- st1b z7.b, p7, [dest, #7, mul vl]
+- ret
+- .endm
++#undef BTI_C
++#define BTI_C
+
+ ENTRY (MEMCPY)
+
+@@ -185,223 +103,209 @@ ENTRY (MEMCPY)
+ PTR_ARG (1)
+ SIZE_ARG (2)
+
+-L(memcpy):
+- cntb vector_length
+- // shortcut for less than vector_length * 8
+- // gives a free ptrue to p0.b for n >= vector_length
+- shortcut_for_small_size L(vl_agnostic)
+- // end of shortcut
+-
+-L(vl_agnostic): // VL Agnostic
+- mov rest, n
+- mov dest_ptr, dest
+- mov src_ptr, src
+- // if rest >= L2_SIZE && vector_length == 64 then L(L2)
+- mov tmp1, 64
+- cmp rest, L2_SIZE
+- ccmp vector_length, tmp1, 0, cs
+- b.eq L(L2)
+-
+-L(unroll8): // unrolling and software pipeline
+- lsl tmp1, vector_length, 3 // vector_length * 8
+- .p2align 3
+- cmp rest, tmp1
+- b.cc L(last)
++ cntb vlen
++ cmp n, vlen, lsl 1
++ b.hi L(copy_small)
++ whilelo p1.b, vlen, n
++ whilelo p0.b, xzr, n
++ 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
++
++L(copy_small):
++ cmp n, vlen, lsl 3
++ b.hi L(copy_large)
++ add dstend, dstin, n
++ add srcend, src, n
++ cmp n, vlen, lsl 2
++ b.hi 1f
++
++ /* Copy 2-4 vectors. */
++ ptrue p0.b
++ ld1b z0.b, p0/z, [src, 0, mul vl]
++ ld1b z1.b, p0/z, [src, 1, mul vl]
++ ld1b z2.b, p0/z, [srcend, -2, mul vl]
++ ld1b z3.b, p0/z, [srcend, -1, mul vl]
++ st1b z0.b, p0, [dstin, 0, mul vl]
++ st1b z1.b, p0, [dstin, 1, mul vl]
++ st1b z2.b, p0, [dstend, -2, mul vl]
++ st1b z3.b, p0, [dstend, -1, mul vl]
++ ret
++
++ .p2align 4
++ /* Copy 4-8 vectors. */
++1: ptrue p0.b
++ ld1b z0.b, p0/z, [src, 0, mul vl]
++ ld1b z1.b, p0/z, [src, 1, mul vl]
++ ld1b z2.b, p0/z, [src, 2, mul vl]
++ ld1b z3.b, p0/z, [src, 3, mul vl]
++ ld1b z4.b, p0/z, [srcend, -4, mul vl]
++ ld1b z5.b, p0/z, [srcend, -3, mul vl]
++ ld1b z6.b, p0/z, [srcend, -2, mul vl]
++ ld1b z7.b, p0/z, [srcend, -1, mul vl]
++ st1b z0.b, p0, [dstin, 0, mul vl]
++ st1b z1.b, p0, [dstin, 1, mul vl]
++ st1b z2.b, p0, [dstin, 2, mul vl]
++ st1b z3.b, p0, [dstin, 3, mul vl]
++ st1b z4.b, p0, [dstend, -4, mul vl]
++ st1b z5.b, p0, [dstend, -3, mul vl]
++ st1b z6.b, p0, [dstend, -2, mul vl]
++ st1b z7.b, p0, [dstend, -1, mul vl]
++ ret
++
++ .p2align 4
++ /* At least 8 vectors - always align to vector length for
++ higher and consistent write performance. */
++L(copy_large):
++ sub tmp, vlen, 1
++ and tmp, dstin, tmp
++ sub tmp, vlen, tmp
++ whilelo p1.b, xzr, tmp
++ ld1b z1.b, p1/z, [src]
++ st1b z1.b, p1, [dstin]
++ add dst, dstin, tmp
++ add src, src, tmp
++ sub n, n, tmp
++ ptrue p0.b
++
++ lsl vlen8, vlen, 3
++ subs n, n, vlen8
++ b.ls 3f
+ ld1b_unroll8
+- add src_ptr, src_ptr, tmp1
+- sub rest, rest, tmp1
+- cmp rest, tmp1
+- b.cc 2f
+- .p2align 3
++ add src, src, vlen8
++ subs n, n, vlen8
++ b.ls 2f
++
++ .p2align 4
++ /* 8x unrolled and software pipelined loop. */
+ 1: stld1b_unroll8
+- add dest_ptr, dest_ptr, tmp1
+- add src_ptr, src_ptr, tmp1
+- sub rest, rest, tmp1
+- cmp rest, tmp1
+- b.ge 1b
++ add dst, dst, vlen8
++ add src, src, vlen8
++ subs n, n, vlen8
++ b.hi 1b
+ 2: st1b_unroll8
+- add dest_ptr, dest_ptr, tmp1
+-
+- .p2align 3
+-L(last):
+- whilelo p0.b, xzr, rest
+- whilelo p1.b, vector_length, rest
+- b.last 1f
+- ld1b z0.b, p0/z, [src_ptr, #0, mul vl]
+- ld1b z1.b, p1/z, [src_ptr, #1, mul vl]
+- st1b z0.b, p0, [dest_ptr, #0, mul vl]
+- st1b z1.b, p1, [dest_ptr, #1, mul vl]
+- ret
+-1: lsl tmp1, vector_length, 1 // vector_length * 2
+- whilelo p2.b, tmp1, rest
+- incb tmp1
+- whilelo p3.b, tmp1, rest
+- b.last 1f
+- ld1b z0.b, p0/z, [src_ptr, #0, mul vl]
+- ld1b z1.b, p1/z, [src_ptr, #1, mul vl]
+- ld1b z2.b, p2/z, [src_ptr, #2, mul vl]
+- ld1b z3.b, p3/z, [src_ptr, #3, mul vl]
+- st1b z0.b, p0, [dest_ptr, #0, mul vl]
+- st1b z1.b, p1, [dest_ptr, #1, mul vl]
+- st1b z2.b, p2, [dest_ptr, #2, mul vl]
+- st1b z3.b, p3, [dest_ptr, #3, mul vl]
++ add dst, dst, vlen8
++3: add n, n, vlen8
++
++ /* Move last 0-8 vectors. */
++L(last_bytes):
++ cmp n, vlen, lsl 1
++ b.hi 1f
++ whilelo p0.b, xzr, n
++ whilelo p1.b, vlen, n
++ ld1b z0.b, p0/z, [src, 0, mul vl]
++ ld1b z1.b, p1/z, [src, 1, mul vl]
++ st1b z0.b, p0, [dst, 0, mul vl]
++ st1b z1.b, p1, [dst, 1, mul vl]
+ ret
+-1: lsl tmp1, vector_length, 2 // vector_length * 4
+- whilelo p4.b, tmp1, rest
+- incb tmp1
+- whilelo p5.b, tmp1, rest
+- incb tmp1
+- whilelo p6.b, tmp1, rest
+- incb tmp1
+- whilelo p7.b, tmp1, rest
+- ld1b z0.b, p0/z, [src_ptr, #0, mul vl]
+- ld1b z1.b, p1/z, [src_ptr, #1, mul vl]
+- ld1b z2.b, p2/z, [src_ptr, #2, mul vl]
+- ld1b z3.b, p3/z, [src_ptr, #3, mul vl]
+- ld1b z4.b, p4/z, [src_ptr, #4, mul vl]
+- ld1b z5.b, p5/z, [src_ptr, #5, mul vl]
+- ld1b z6.b, p6/z, [src_ptr, #6, mul vl]
+- ld1b z7.b, p7/z, [src_ptr, #7, mul vl]
+- st1b z0.b, p0, [dest_ptr, #0, mul vl]
+- st1b z1.b, p1, [dest_ptr, #1, mul vl]
+- st1b z2.b, p2, [dest_ptr, #2, mul vl]
+- st1b z3.b, p3, [dest_ptr, #3, mul vl]
+- st1b z4.b, p4, [dest_ptr, #4, mul vl]
+- st1b z5.b, p5, [dest_ptr, #5, mul vl]
+- st1b z6.b, p6, [dest_ptr, #6, mul vl]
+- st1b z7.b, p7, [dest_ptr, #7, mul vl]
++
++ .p2align 4
++
++1: add srcend, src, n
++ add dstend, dst, n
++ ld1b z0.b, p0/z, [src, 0, mul vl]
++ ld1b z1.b, p0/z, [src, 1, mul vl]
++ ld1b z2.b, p0/z, [srcend, -2, mul vl]
++ ld1b z3.b, p0/z, [srcend, -1, mul vl]
++ cmp n, vlen, lsl 2
++ b.hi 1f
++
++ st1b z0.b, p0, [dst, 0, mul vl]
++ st1b z1.b, p0, [dst, 1, mul vl]
++ st1b z2.b, p0, [dstend, -2, mul vl]
++ st1b z3.b, p0, [dstend, -1, mul vl]
+ ret
+
+-L(L2):
+- // align dest address at CACHE_LINE_SIZE byte boundary
+- mov tmp1, CACHE_LINE_SIZE
+- ands tmp2, dest_ptr, CACHE_LINE_SIZE - 1
+- // if cl_remainder == 0
+- b.eq L(L2_dc_zva)
+- sub cl_remainder, tmp1, tmp2
+- // process remainder until the first CACHE_LINE_SIZE boundary
+- whilelo p1.b, xzr, cl_remainder // keep p0.b all true
+- whilelo p2.b, vector_length, cl_remainder
+- b.last 1f
+- ld1b z1.b, p1/z, [src_ptr, #0, mul vl]
+- ld1b z2.b, p2/z, [src_ptr, #1, mul vl]
+- st1b z1.b, p1, [dest_ptr, #0, mul vl]
+- st1b z2.b, p2, [dest_ptr, #1, mul vl]
+- b 2f
+-1: lsl tmp1, vector_length, 1 // vector_length * 2
+- whilelo p3.b, tmp1, cl_remainder
+- incb tmp1
+- whilelo p4.b, tmp1, cl_remainder
+- ld1b z1.b, p1/z, [src_ptr, #0, mul vl]
+- ld1b z2.b, p2/z, [src_ptr, #1, mul vl]
+- ld1b z3.b, p3/z, [src_ptr, #2, mul vl]
+- ld1b z4.b, p4/z, [src_ptr, #3, mul vl]
+- st1b z1.b, p1, [dest_ptr, #0, mul vl]
+- st1b z2.b, p2, [dest_ptr, #1, mul vl]
+- st1b z3.b, p3, [dest_ptr, #2, mul vl]
+- st1b z4.b, p4, [dest_ptr, #3, mul vl]
+-2: add dest_ptr, dest_ptr, cl_remainder
+- add src_ptr, src_ptr, cl_remainder
+- sub rest, rest, cl_remainder
+-
+-L(L2_dc_zva):
+- // zero fill
+- and tmp1, dest, 0xffffffffffffff
+- and tmp2, src, 0xffffffffffffff
+- subs tmp1, tmp1, tmp2 // diff
+- b.ge 1f
+- neg tmp1, tmp1
+-1: mov tmp3, ZF_DIST + CACHE_LINE_SIZE * 2
+- cmp tmp1, tmp3
+- b.lo L(unroll8)
+- mov tmp1, dest_ptr
+- dc_zva (ZF_DIST / CACHE_LINE_SIZE) - 1
+- // unroll
+- ld1b_unroll8 // this line has to be after "b.lo L(unroll8)"
+- add src_ptr, src_ptr, CACHE_LINE_SIZE * 2
+- sub rest, rest, CACHE_LINE_SIZE * 2
+- mov tmp1, ZF_DIST
+- .p2align 3
+-1: stld1b_unroll4a
+- add tmp2, dest_ptr, tmp1 // dest_ptr + ZF_DIST
+- dc zva, tmp2
+- stld1b_unroll4b
+- add tmp2, tmp2, CACHE_LINE_SIZE
+- dc zva, tmp2
+- add dest_ptr, dest_ptr, CACHE_LINE_SIZE * 2
+- add src_ptr, src_ptr, CACHE_LINE_SIZE * 2
+- sub rest, rest, CACHE_LINE_SIZE * 2
+- cmp rest, tmp3 // ZF_DIST + CACHE_LINE_SIZE * 2
+- b.ge 1b
+- st1b_unroll8
+- add dest_ptr, dest_ptr, CACHE_LINE_SIZE * 2
+- b L(unroll8)
++1: ld1b z4.b, p0/z, [src, 2, mul vl]
++ ld1b z5.b, p0/z, [src, 3, mul vl]
++ ld1b z6.b, p0/z, [srcend, -4, mul vl]
++ ld1b z7.b, p0/z, [srcend, -3, mul vl]
++ st1b z0.b, p0, [dst, 0, mul vl]
++ st1b z1.b, p0, [dst, 1, mul vl]
++ st1b z4.b, p0, [dst, 2, mul vl]
++ st1b z5.b, p0, [dst, 3, mul vl]
++ st1b z6.b, p0, [dstend, -4, mul vl]
++ st1b z7.b, p0, [dstend, -3, mul vl]
++ st1b z2.b, p0, [dstend, -2, mul vl]
++ st1b z3.b, p0, [dstend, -1, mul vl]
++ ret
+
+ END (MEMCPY)
+ libc_hidden_builtin_def (MEMCPY)
+
+
+-ENTRY (MEMMOVE)
++ENTRY_ALIGN (MEMMOVE, 4)
+
+ PTR_ARG (0)
+ PTR_ARG (1)
+ SIZE_ARG (2)
+
+- // remove tag address
+- // dest has to be immutable because it is the return value
+- // src has to be immutable because it is used in L(bwd_last)
+- and tmp2, dest, 0xffffffffffffff // save dest_notag into tmp2
+- and tmp3, src, 0xffffffffffffff // save src_notag intp tmp3
+- cmp n, 0
+- ccmp tmp2, tmp3, 4, ne
+- b.ne 1f
++ /* Fast case for up to 2 vectors. */
++ cntb vlen
++ cmp n, vlen, lsl 1
++ b.hi 1f
++ whilelo p0.b, xzr, n
++ whilelo p1.b, vlen, n
++ 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]
++L(full_overlap):
+ ret
+-1: cntb vector_length
+- // shortcut for less than vector_length * 8
+- // gives a free ptrue to p0.b for n >= vector_length
+- // tmp2 and tmp3 should not be used in this macro to keep
+- // notag addresses
+- shortcut_for_small_size L(dispatch)
+- // end of shortcut
+-
+-L(dispatch):
+- // tmp2 = dest_notag, tmp3 = src_notag
+- // diff = dest_notag - src_notag
+- sub tmp1, tmp2, tmp3
+- // if diff <= 0 || diff >= n then memcpy
+- cmp tmp1, 0
+- ccmp tmp1, n, 2, gt
+- b.cs L(vl_agnostic)
+-
+-L(bwd_start):
+- mov rest, n
+- add dest_ptr, dest, n // dest_end
+- add src_ptr, src, n // src_end
+-
+-L(bwd_unroll8): // unrolling and software pipeline
+- lsl tmp1, vector_length, 3 // vector_length * 8
+- .p2align 3
+- cmp rest, tmp1
+- b.cc L(bwd_last)
+- sub src_ptr, src_ptr, tmp1
++
++ .p2align 4
++ /* Check for overlapping moves. Return if there is a full overlap.
++ Small moves up to 8 vectors use the overlap-safe copy_small code.
++ Non-overlapping or overlapping moves with dst < src use memcpy.
++ Overlapping moves with dst > src use a backward copy loop. */
++1: sub tmp, dstin, src
++ ands tmp, tmp, 0xffffffffffffff /* Clear special tag bits. */
++ b.eq L(full_overlap)
++ cmp n, vlen, lsl 3
++ b.ls L(copy_small)
++ cmp tmp, n
++ b.hs L(copy_large)
++
++ /* Align to vector length. */
++ add dst, dstin, n
++ sub tmp, vlen, 1
++ ands tmp, dst, tmp
++ csel tmp, tmp, vlen, ne
++ whilelo p1.b, xzr, tmp
++ sub n, n, tmp
++ ld1b z1.b, p1/z, [src, n]
++ st1b z1.b, p1, [dstin, n]
++ add src, src, n
++ add dst, dstin, n
++
++ ptrue p0.b
++ lsl vlen8, vlen, 3
++ subs n, n, vlen8
++ b.ls 3f
++ sub src, src, vlen8
+ ld1b_unroll8
+- sub rest, rest, tmp1
+- cmp rest, tmp1
+- b.cc 2f
+- .p2align 3
+-1: sub src_ptr, src_ptr, tmp1
+- sub dest_ptr, dest_ptr, tmp1
++ subs n, n, vlen8
++ b.ls 2f
++
++ .p2align 4
++ /* 8x unrolled and software pipelined backward copy loop. */
++1: sub src, src, vlen8
++ sub dst, dst, vlen8
+ stld1b_unroll8
+- sub rest, rest, tmp1
+- cmp rest, tmp1
+- b.ge 1b
+-2: sub dest_ptr, dest_ptr, tmp1
++ subs n, n, vlen8
++ b.hi 1b
++2: sub dst, dst, vlen8
+ st1b_unroll8
++3: add n, n, vlen8
+
+-L(bwd_last):
+- mov dest_ptr, dest
+- mov src_ptr, src
+- b L(last)
++ /* Adjust src/dst for last 0-8 vectors. */
++ sub src, src, n
++ mov dst, dstin
++ b L(last_bytes)
+
+ END (MEMMOVE)
+ libc_hidden_builtin_def (MEMMOVE)
+--
+2.31.1
+
diff --git a/glibc-rh2047981-1.patch b/glibc-rh2047981-1.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e1a085d66afb58a4dbc354c3e7f2031b509e6dbe
--- /dev/null
+++ b/glibc-rh2047981-1.patch
@@ -0,0 +1,98 @@
+commit eb77a1fccc7e60cea32245c11288c7f1d92545fa
+Author: Florian Weimer
+Date: Wed Oct 16 18:19:51 2019 +0200
+
+ dlfcn: Remove remnants of caller sensitivity from dlinfo
+
+ dlinfo operates on a specific handle, which means that there is no
+ caller sensivity involved.
+
+diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c
+index 964572cc670ceba4..23ef3f57ca41afdf 100644
+--- a/dlfcn/dlinfo.c
++++ b/dlfcn/dlinfo.c
+@@ -26,7 +26,7 @@
+ int
+ dlinfo (void *handle, int request, void *arg)
+ {
+- return __dlinfo (handle, request, arg, RETURN_ADDRESS (0));
++ return __dlinfo (handle, request, arg);
+ }
+
+ #else
+@@ -35,7 +35,6 @@ dlinfo (void *handle, int request, void *arg)
+
+ struct dlinfo_args
+ {
+- ElfW(Addr) caller;
+ void *handle;
+ int request;
+ void *arg;
+@@ -47,24 +46,6 @@ dlinfo_doit (void *argsblock)
+ struct dlinfo_args *const args = argsblock;
+ struct link_map *l = args->handle;
+
+-# if 0
+- if (args->handle == RTLD_SELF)
+- {
+- Lmid_t nsid;
+-
+- /* Find the highest-addressed object that CALLER is not below. */
+- for (nsid = 0; nsid < DL_NNS; ++nsid)
+- for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
+- if (caller >= l->l_map_start && caller < l->l_map_end
+- && (l->l_contiguous || _dl_addr_inside_object (l, caller)))
+- break;
+-
+- if (l == NULL)
+- _dl_signal_error (0, NULL, NULL, N_("\
+-RTLD_SELF used in code not dynamically loaded"));
+- }
+-# endif
+-
+ switch (args->request)
+ {
+ case RTLD_DI_CONFIGADDR:
+@@ -108,16 +89,14 @@ RTLD_SELF used in code not dynamically loaded"));
+ }
+
+ int
+-__dlinfo (void *handle, int request, void *arg DL_CALLER_DECL)
++__dlinfo (void *handle, int request, void *arg)
+ {
+ # ifdef SHARED
+ if (!rtld_active ())
+- return _dlfcn_hook->dlinfo (handle, request, arg,
+- DL_CALLER);
++ return _dlfcn_hook->dlinfo (handle, request, arg);
+ # endif
+
+- struct dlinfo_args args = { (ElfW(Addr)) DL_CALLER,
+- handle, request, arg };
++ struct dlinfo_args args = { handle, request, arg };
+ return _dlerror_run (&dlinfo_doit, &args) ? -1 : 0;
+ }
+ # ifdef SHARED
+diff --git a/include/dlfcn.h b/include/dlfcn.h
+index 0dc57dbe2217cfe7..93dd369ab12a5745 100644
+--- a/include/dlfcn.h
++++ b/include/dlfcn.h
+@@ -117,7 +117,7 @@ struct dlfcn_hook
+ int (*dladdr) (const void *address, Dl_info *info);
+ int (*dladdr1) (const void *address, Dl_info *info,
+ void **extra_info, int flags);
+- int (*dlinfo) (void *handle, int request, void *arg, void *dl_caller);
++ int (*dlinfo) (void *handle, int request, void *arg);
+ void *(*dlmopen) (Lmid_t nsid, const char *file, int mode, void *dl_caller);
+ void *pad[4];
+ };
+@@ -143,8 +143,7 @@ extern int __dladdr (const void *address, Dl_info *info)
+ extern int __dladdr1 (const void *address, Dl_info *info,
+ void **extra_info, int flags)
+ attribute_hidden;
+-extern int __dlinfo (void *handle, int request, void *arg DL_CALLER_DECL)
+- attribute_hidden;
++extern int __dlinfo (void *handle, int request, void *arg) attribute_hidden;
+
+ #ifndef SHARED
+ struct link_map;
diff --git a/glibc-rh2047981-10.patch b/glibc-rh2047981-10.patch
new file mode 100644
index 0000000000000000000000000000000000000000..00b7a710778b83b265e04b55dae95e6f5c673945
--- /dev/null
+++ b/glibc-rh2047981-10.patch
@@ -0,0 +1,31 @@
+commit 88361b408b9dbd313f15413cc2e6be0f1cafb01a
+Author: H.J. Lu
+Date: Tue Aug 17 19:36:04 2021 -0700
+
+ elf: Copy l_addr/l_ld when adding ld.so to a new namespace
+
+ When add ld.so to a new namespace, we don't actually load ld.so. We
+ create a new link map and refers the real one for almost everything.
+ Copy l_addr and l_ld from the real ld.so link map to avoid GDB warning:
+
+ warning: .dynamic section for ".../elf/ld-linux-x86-64.so.2" is not at the expected address (wrong library or version mismatch?)
+
+ when handling shared library loaded by dlmopen.
+
+ Reviewed-by: Adhemerval Zanella
+
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index cdb5d4b5b67f1ca1..303e6594f9af9b7e 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -932,6 +932,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
+ /* Refer to the real descriptor. */
+ l->l_real = &GL(dl_rtld_map);
+
++ /* Copy l_addr and l_ld to avoid a GDB warning with dlmopen(). */
++ l->l_addr = l->l_real->l_addr;
++ l->l_ld = l->l_real->l_ld;
++
+ /* No need to bump the refcount of the real object, ld.so will
+ never be unloaded. */
+ __close_nocancel (fd);
diff --git a/glibc-rh2047981-11.patch b/glibc-rh2047981-11.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a0cde6c045a4f91dc3c444e41502615784200b71
--- /dev/null
+++ b/glibc-rh2047981-11.patch
@@ -0,0 +1,45 @@
+commit 1e1ecea62e899acb58c3fdf3b320a0833ddd0dff
+Author: H.J. Lu
+Date: Thu Sep 30 10:29:17 2021 -0700
+
+ elf: Replace nsid with args.nsid [BZ #27609]
+
+ commit ec935dea6332cb22f9881cd1162bad156173f4b0
+ Author: Florian Weimer
+ Date: Fri Apr 24 22:31:15 2020 +0200
+
+ elf: Implement __libc_early_init
+
+ has
+
+ @@ -856,6 +876,11 @@ no more namespaces available for dlmopen()"));
+ /* See if an error occurred during loading. */
+ if (__glibc_unlikely (exception.errstring != NULL))
+ {
+ + /* Avoid keeping around a dangling reference to the libc.so link
+ + map in case it has been cached in libc_map. */
+ + if (!args.libc_already_loaded)
+ + GL(dl_ns)[nsid].libc_map = NULL;
+ +
+
+ do_dlopen calls _dl_open with nsid == __LM_ID_CALLER (-2), which calls
+ dl_open_worker with args.nsid = nsid. dl_open_worker updates args.nsid
+ if it is __LM_ID_CALLER. After dl_open_worker returns, it is wrong to
+ use nsid.
+
+ Replace nsid with args.nsid after dl_open_worker returns. This fixes
+ BZ #27609.
+
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index 661a2172d1789b26..b5a4da04907d8d29 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -916,7 +916,7 @@ no more namespaces available for dlmopen()"));
+ /* Avoid keeping around a dangling reference to the libc.so link
+ map in case it has been cached in libc_map. */
+ if (!args.libc_already_loaded)
+- GL(dl_ns)[nsid].libc_map = NULL;
++ GL(dl_ns)[args.nsid].libc_map = NULL;
+
+ /* Remove the object from memory. It may be in an inconsistent
+ state if relocation failed, for example. */
diff --git a/glibc-rh2047981-12.patch b/glibc-rh2047981-12.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8588aaae7d06343f1a993e25f2c7e3287faf79e0
--- /dev/null
+++ b/glibc-rh2047981-12.patch
@@ -0,0 +1,607 @@
+This is a partial backport of this commit with only the 'scope'
+refactoring required to have access to the outer scope value
+to use with RESOLVE_MAP to implement la_symbind for BIND_NOW.
+
+We do not backport this entire patch because the nested function
+changes have significant impact on code generation and would
+require furhter backports to support and maintain.
+
+commit 490e6c62aa31a8aa5c4a059f6e646ede121edf0a
+Author: Fangrui Song
+Date: Thu Oct 7 11:55:02 2021 -0700
+
+ elf: Avoid nested functions in the loader [BZ #27220]
+
+ dynamic-link.h is included more than once in some elf/ files (rtld.c,
+ dl-conflict.c, dl-reloc.c, dl-reloc-static-pie.c) and uses GCC nested
+ functions. This harms readability and the nested functions usage
+ is the biggest obstacle prevents Clang build (Clang doesn't support GCC
+ nested functions).
+
+ The key idea for unnesting is to add extra parameters (struct link_map
+ *and struct r_scope_elm *[]) to RESOLVE_MAP,
+ ELF_MACHINE_BEFORE_RTLD_RELOC, ELF_DYNAMIC_RELOCATE, elf_machine_rel[a],
+ elf_machine_lazy_rel, and elf_machine_runtime_setup. (This is inspired
+ by Stan Shebs' ppc64/x86-64 implementation in the
+ google/grte/v5-2.27/master which uses mixed extra parameters and static
+ variables.)
+
+ Future simplification:
+ * If mips elf_machine_runtime_setup no longer needs RESOLVE_GOTSYM,
+ elf_machine_runtime_setup can drop the `scope` parameter.
+ * If TLSDESC no longer need to be in elf_machine_lazy_rel,
+ elf_machine_lazy_rel can drop the `scope` parameter.
+
+ Tested on aarch64, i386, x86-64, powerpc64le, powerpc64, powerpc32,
+ sparc64, sparcv9, s390x, s390, hppa, ia64, armhf, alpha, and mips64.
+ In addition, tested build-many-glibcs.py with {arc,csky,microblaze,nios2}-linux-gnu
+ and riscv64-linux-gnu-rv64imafdc-lp64d.
+
+ Reviewed-by: Adhemerval Zanella
+
+diff --git a/elf/dl-conflict.c b/elf/dl-conflict.c
+index 70f14b04cd383048..31d87ac846427752 100644
+--- a/elf/dl-conflict.c
++++ b/elf/dl-conflict.c
+@@ -40,7 +40,7 @@ _dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict,
+ data. */
+
+ /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */
+-#define RESOLVE_MAP(ref, version, flags) (*ref = NULL, NULL)
++#define RESOLVE_MAP(map, scope, ref, version, flags) (*ref = NULL, NULL)
+ #define RESOLVE(ref, version, flags) (*ref = NULL, 0)
+ #define RESOLVE_CONFLICT_FIND_MAP(map, r_offset) \
+ do { \
+@@ -67,8 +67,8 @@ _dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict,
+ GL(dl_num_cache_relocations) += conflictend - conflict;
+
+ for (; conflict < conflictend; ++conflict)
+- elf_machine_rela (l, conflict, NULL, NULL, (void *) conflict->r_offset,
+- 0);
++ elf_machine_rela (l, NULL, conflict, NULL, NULL,
++ (void *) conflict->r_offset, 0);
+ }
+ #endif
+ }
+diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
+index ab1ce0eacced9d2b..1efbf515c3c1c16d 100644
+--- a/elf/dl-reloc-static-pie.c
++++ b/elf/dl-reloc-static-pie.c
+@@ -30,7 +30,7 @@ _dl_relocate_static_pie (void)
+
+ # define STATIC_PIE_BOOTSTRAP
+ # define BOOTSTRAP_MAP (main_map)
+-# define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP
++# define RESOLVE_MAP(map, scope, sym, version, flags) BOOTSTRAP_MAP
+ # include "dynamic-link.h"
+
+ /* Figure out the run-time load address of static PIE. */
+@@ -46,7 +46,7 @@ _dl_relocate_static_pie (void)
+
+ /* Relocate ourselves so we can do normal function calls and
+ data access using the global offset table. */
+- ELF_DYNAMIC_RELOCATE (main_map, 0, 0, 0);
++ ELF_DYNAMIC_RELOCATE (main_map, NULL, 0, 0, 0);
+ main_map->l_relocated = 1;
+
+ /* Initialize _r_debug. */
+diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
+index c6139b89d4ecddc8..19de5de067a5ef07 100644
+--- a/elf/dl-reloc.c
++++ b/elf/dl-reloc.c
+@@ -250,7 +250,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+ const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
+
+ /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */
+-#define RESOLVE_MAP(ref, version, r_type) \
++#define RESOLVE_MAP(l, scope, ref, version, r_type) \
+ ((ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \
+ && __glibc_likely (!dl_symbol_visibility_binds_local_p (*ref))) \
+ ? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0) \
+@@ -275,7 +275,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+
+ #include "dynamic-link.h"
+
+- ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling, skip_ifunc);
++ ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc);
+
+ #ifndef PROF
+ if (__glibc_unlikely (consider_profiling)
+diff --git a/elf/do-rel.h b/elf/do-rel.h
+index 19cb5d236ee30698..0b04d1a0bf28b9f4 100644
+--- a/elf/do-rel.h
++++ b/elf/do-rel.h
+@@ -38,7 +38,7 @@
+ than fully resolved now. */
+
+ auto inline void __attribute__ ((always_inline))
+-elf_dynamic_do_Rel (struct link_map *map,
++elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
+ ElfW(Addr) reladdr, ElfW(Addr) relsize,
+ __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative,
+ int lazy, int skip_ifunc)
+@@ -68,13 +68,13 @@ elf_dynamic_do_Rel (struct link_map *map,
+ }
+ else
+ # endif
+- elf_machine_lazy_rel (map, l_addr, r, skip_ifunc);
++ elf_machine_lazy_rel (map, scope, l_addr, r, skip_ifunc);
+
+ # ifdef ELF_MACHINE_IRELATIVE
+ if (r2 != NULL)
+ for (; r2 <= end2; ++r2)
+ if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
+- elf_machine_lazy_rel (map, l_addr, r2, skip_ifunc);
++ elf_machine_lazy_rel (map, scope, l_addr, r2, skip_ifunc);
+ # endif
+ }
+ else
+@@ -134,7 +134,7 @@ elf_dynamic_do_Rel (struct link_map *map,
+ #endif
+
+ ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
+- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
++ elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)],
+ &map->l_versions[ndx],
+ (void *) (l_addr + r->r_offset), skip_ifunc);
+ }
+@@ -146,7 +146,7 @@ elf_dynamic_do_Rel (struct link_map *map,
+ {
+ ElfW(Half) ndx
+ = version[ELFW(R_SYM) (r2->r_info)] & 0x7fff;
+- elf_machine_rel (map, r2,
++ elf_machine_rel (map, scope, r2,
+ &symtab[ELFW(R_SYM) (r2->r_info)],
+ &map->l_versions[ndx],
+ (void *) (l_addr + r2->r_offset),
+@@ -167,14 +167,14 @@ elf_dynamic_do_Rel (struct link_map *map,
+ }
+ else
+ # endif
+- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
++ elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
+ (void *) (l_addr + r->r_offset), skip_ifunc);
+
+ # ifdef ELF_MACHINE_IRELATIVE
+ if (r2 != NULL)
+ for (; r2 <= end2; ++r2)
+ if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
+- elf_machine_rel (map, r2, &symtab[ELFW(R_SYM) (r2->r_info)],
++ elf_machine_rel (map, scope, r2, &symtab[ELFW(R_SYM) (r2->r_info)],
+ NULL, (void *) (l_addr + r2->r_offset),
+ skip_ifunc);
+ # endif
+diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
+index 2fc3c91b7defe84e..357a2e3c6825e0fc 100644
+--- a/elf/dynamic-link.h
++++ b/elf/dynamic-link.h
+@@ -60,8 +60,9 @@ int _dl_try_allocate_static_tls (struct link_map *map, bool optional)
+ unaligned cases. */
+ # if ! ELF_MACHINE_NO_REL
+ auto inline void __attribute__((always_inline))
+-elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
+- const ElfW(Sym) *sym, const struct r_found_version *version,
++elf_machine_rel (struct link_map *map, struct r_scope_elem *scope[],
++ const ElfW(Rel) *reloc, const ElfW(Sym) *sym,
++ const struct r_found_version *version,
+ void *const reloc_addr, int skip_ifunc);
+ auto inline void __attribute__((always_inline))
+ elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
+@@ -69,8 +70,9 @@ elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
+ # endif
+ # if ! ELF_MACHINE_NO_RELA
+ auto inline void __attribute__((always_inline))
+-elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
+- const ElfW(Sym) *sym, const struct r_found_version *version,
++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
++ const ElfW(Rela) *reloc, const ElfW(Sym) *sym,
++ const struct r_found_version *version,
+ void *const reloc_addr, int skip_ifunc);
+ auto inline void __attribute__((always_inline))
+ elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+@@ -78,12 +80,12 @@ elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+ # endif
+ # if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
+ auto inline void __attribute__((always_inline))
+-elf_machine_lazy_rel (struct link_map *map,
++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
+ ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
+ int skip_ifunc);
+ # else
+ auto inline void __attribute__((always_inline))
+-elf_machine_lazy_rel (struct link_map *map,
++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
+ ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+ int skip_ifunc);
+ # endif
+@@ -114,7 +116,7 @@ elf_machine_lazy_rel (struct link_map *map,
+ consumes precisely the very end of the DT_REL*, or DT_JMPREL and DT_REL*
+ are completely separate and there is a gap between them. */
+
+-# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \
++# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, scope, do_lazy, skip_ifunc, test_rel) \
+ do { \
+ struct { ElfW(Addr) start, size; \
+ __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
+@@ -152,13 +154,13 @@ elf_machine_lazy_rel (struct link_map *map,
+ } \
+ \
+ if (ELF_DURING_STARTUP) \
+- elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, \
++ elf_dynamic_do_##reloc ((map), scope, ranges[0].start, ranges[0].size, \
+ ranges[0].nrelative, 0, skip_ifunc); \
+ else \
+ { \
+ int ranges_index; \
+ for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
+- elf_dynamic_do_##reloc ((map), \
++ elf_dynamic_do_##reloc ((map), scope, \
+ ranges[ranges_index].start, \
+ ranges[ranges_index].size, \
+ ranges[ranges_index].nrelative, \
+@@ -175,29 +177,29 @@ elf_machine_lazy_rel (struct link_map *map,
+
+ # if ! ELF_MACHINE_NO_REL
+ # include "do-rel.h"
+-# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) \
+- _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, lazy, skip_ifunc, _ELF_CHECK_REL)
++# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc) \
++ _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, skip_ifunc, _ELF_CHECK_REL)
+ # else
+-# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) /* Nothing to do. */
++# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc) /* Nothing to do. */
+ # endif
+
+ # if ! ELF_MACHINE_NO_RELA
+ # define DO_RELA
+ # include "do-rel.h"
+-# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) \
+- _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, lazy, skip_ifunc, _ELF_CHECK_REL)
++# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) \
++ _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, skip_ifunc, _ELF_CHECK_REL)
+ # else
+-# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) /* Nothing to do. */
++# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) /* Nothing to do. */
+ # endif
+
+ /* This can't just be an inline function because GCC is too dumb
+ to inline functions containing inlines themselves. */
+-# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile, skip_ifunc) \
++# define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \
+ do { \
+- int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
++ int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy), \
+ (consider_profile)); \
+- ELF_DYNAMIC_DO_REL ((map), edr_lazy, skip_ifunc); \
+- ELF_DYNAMIC_DO_RELA ((map), edr_lazy, skip_ifunc); \
++ ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc); \
++ ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc); \
+ } while (0)
+
+ #endif
+diff --git a/elf/rtld.c b/elf/rtld.c
+index e107af4014d43777..f3836b8a78faaf27 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -514,7 +514,7 @@ _dl_start (void *arg)
+ is trivial: always the map of ld.so itself. */
+ #define RTLD_BOOTSTRAP
+ #define BOOTSTRAP_MAP (&bootstrap_map)
+-#define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP
++#define RESOLVE_MAP(map, scope, sym, version, flags) BOOTSTRAP_MAP
+ #include "dynamic-link.h"
+
+ #ifdef DONT_USE_BOOTSTRAP_MAP
+@@ -560,7 +560,7 @@ _dl_start (void *arg)
+ /* Relocate ourselves so we can do normal function calls and
+ data access using the global offset table. */
+
+- ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0, 0);
++ ELF_DYNAMIC_RELOCATE (&bootstrap_map, NULL, 0, 0, 0);
+ }
+ bootstrap_map.l_relocated = 1;
+
+diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
+index 3fd3c8a265d012b1..5eab544afe2717f7 100644
+--- a/sysdeps/aarch64/dl-machine.h
++++ b/sysdeps/aarch64/dl-machine.h
+@@ -65,7 +65,8 @@ elf_machine_load_address (void)
+ entries will jump to the on-demand fixup code in dl-runtime.c. */
+
+ static inline int __attribute__ ((unused))
+-elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
++elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
++ int lazy, int profile)
+ {
+ if (l->l_info[DT_JMPREL] && lazy)
+ {
+@@ -242,8 +243,9 @@ elf_machine_plt_value (struct link_map *map,
+
+ auto inline void
+ __attribute__ ((always_inline))
+-elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
+- const ElfW(Sym) *sym, const struct r_found_version *version,
++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
++ const ElfW(Rela) *reloc, const ElfW(Sym) *sym,
++ const struct r_found_version *version,
+ void *const reloc_addr_arg, int skip_ifunc)
+ {
+ ElfW(Addr) *const reloc_addr = reloc_addr_arg;
+@@ -256,7 +258,8 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
+ else
+ {
+ const ElfW(Sym) *const refsym = sym;
+- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
++ r_type);
+ ElfW(Addr) value = SYMBOL_ADDRESS (sym_map, sym, true);
+
+ if (sym != NULL
+@@ -381,7 +384,7 @@ elf_machine_rela_relative (ElfW(Addr) l_addr,
+
+ inline void
+ __attribute__ ((always_inline))
+-elf_machine_lazy_rel (struct link_map *map,
++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
+ ElfW(Addr) l_addr,
+ const ElfW(Rela) *reloc,
+ int skip_ifunc)
+@@ -408,7 +411,7 @@ elf_machine_lazy_rel (struct link_map *map,
+ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+ version = &map->l_versions[vernum[symndx] & 0x7fff];
+ }
+- elf_machine_rela (map, reloc, sym, version, reloc_addr,
++ elf_machine_rela (map, scope, reloc, sym, version, reloc_addr,
+ skip_ifunc);
+ return;
+ }
+@@ -435,7 +438,7 @@ elf_machine_lazy_rel (struct link_map *map,
+
+ /* Always initialize TLS descriptors completely, because lazy
+ initialization requires synchronization at every TLS access. */
+- elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc);
++ elf_machine_rela (map, scope, reloc, sym, version, reloc_addr, skip_ifunc);
+ }
+ else if (__glibc_unlikely (r_type == AARCH64_R(IRELATIVE)))
+ {
+diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
+index 3a30671591284d79..5ba95b9e4af49942 100644
+--- a/sysdeps/i386/dl-machine.h
++++ b/sysdeps/i386/dl-machine.h
+@@ -61,7 +61,8 @@ elf_machine_load_address (void)
+ entries will jump to the on-demand fixup code in dl-runtime.c. */
+
+ static inline int __attribute__ ((unused, always_inline))
+-elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
++elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
++ int lazy, int profile)
+ {
+ Elf32_Addr *got;
+ extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
+@@ -293,8 +294,9 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
+
+ auto inline void
+ __attribute ((always_inline))
+-elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
+- const Elf32_Sym *sym, const struct r_found_version *version,
++elf_machine_rel (struct link_map *map, struct r_scope_elem *scope[],
++ const Elf32_Rel *reloc, const Elf32_Sym *sym,
++ const struct r_found_version *version,
+ void *const reloc_addr_arg, int skip_ifunc)
+ {
+ Elf32_Addr *const reloc_addr = reloc_addr_arg;
+@@ -327,7 +329,8 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
+ # ifndef RTLD_BOOTSTRAP
+ const Elf32_Sym *const refsym = sym;
+ # endif
+- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
++ r_type);
+ Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
+
+ if (sym != NULL
+@@ -493,8 +496,9 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
+ # ifndef RTLD_BOOTSTRAP
+ auto inline void
+ __attribute__ ((always_inline))
+-elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
+- const Elf32_Sym *sym, const struct r_found_version *version,
++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
++ const Elf32_Rela *reloc, const Elf32_Sym *sym,
++ const struct r_found_version *version,
+ void *const reloc_addr_arg, int skip_ifunc)
+ {
+ Elf32_Addr *const reloc_addr = reloc_addr_arg;
+@@ -507,7 +511,8 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
+ # ifndef RESOLVE_CONFLICT_FIND_MAP
+ const Elf32_Sym *const refsym = sym;
+ # endif
+- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
++ r_type);
+ Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
+
+ if (sym != NULL
+@@ -661,7 +666,7 @@ elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
+
+ auto inline void
+ __attribute__ ((always_inline))
+-elf_machine_lazy_rel (struct link_map *map,
++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
+ Elf32_Addr l_addr, const Elf32_Rel *reloc,
+ int skip_ifunc)
+ {
+@@ -696,13 +701,13 @@ elf_machine_lazy_rel (struct link_map *map,
+ const ElfW(Half) *const version =
+ (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+ ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
+- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
++ elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)],
+ &map->l_versions[ndx],
+ (void *) (l_addr + r->r_offset), skip_ifunc);
+ }
+ # ifndef RTLD_BOOTSTRAP
+ else
+- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
++ elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
+ (void *) (l_addr + r->r_offset), skip_ifunc);
+ # endif
+ }
+@@ -721,7 +726,7 @@ elf_machine_lazy_rel (struct link_map *map,
+
+ auto inline void
+ __attribute__ ((always_inline))
+-elf_machine_lazy_rela (struct link_map *map,
++elf_machine_lazy_rela (struct link_map *map, struct r_scope_elem *scope[],
+ Elf32_Addr l_addr, const Elf32_Rela *reloc,
+ int skip_ifunc)
+ {
+@@ -745,7 +750,8 @@ elf_machine_lazy_rela (struct link_map *map,
+
+ /* Always initialize TLS descriptors completely at load time, in
+ case static TLS is allocated for it that requires locking. */
+- elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc);
++ elf_machine_rela (map, scope, reloc, sym, version, reloc_addr,
++ skip_ifunc);
+ }
+ else if (__glibc_unlikely (r_type == R_386_IRELATIVE))
+ {
+diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h
+index 99a83d0c82ea0a9c..35996bb9173da231 100644
+--- a/sysdeps/powerpc/powerpc64/dl-machine.h
++++ b/sysdeps/powerpc/powerpc64/dl-machine.h
+@@ -345,7 +345,8 @@ dl_platform_init (void)
+ /* Set up the loaded object described by MAP so its unrelocated PLT
+ entries will jump to the on-demand fixup code in dl-runtime.c. */
+ static inline int __attribute__ ((always_inline))
+-elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
++elf_machine_runtime_setup (struct link_map *map, struct r_scope_elem *scope[],
++ int lazy, int profile)
+ {
+ if (map->l_info[DT_JMPREL])
+ {
+@@ -679,7 +680,7 @@ resolve_ifunc (Elf64_Addr value,
+ /* Perform the relocation specified by RELOC and SYM (which is fully
+ resolved). MAP is the object containing the reloc. */
+ auto inline void __attribute__ ((always_inline))
+-elf_machine_rela (struct link_map *map,
++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
+ const Elf64_Rela *reloc,
+ const Elf64_Sym *sym,
+ const struct r_found_version *version,
+@@ -707,7 +708,7 @@ elf_machine_rela (struct link_map *map,
+
+ /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt
+ and STT_GNU_IFUNC. */
+- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, r_type);
+ Elf64_Addr value = SYMBOL_ADDRESS (sym_map, sym, true) + reloc->r_addend;
+
+ if (sym != NULL
+@@ -1036,7 +1037,7 @@ elf_machine_rela (struct link_map *map,
+ }
+
+ auto inline void __attribute__ ((always_inline))
+-elf_machine_lazy_rel (struct link_map *map,
++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
+ Elf64_Addr l_addr, const Elf64_Rela *reloc,
+ int skip_ifunc)
+ {
+diff --git a/sysdeps/s390/s390-64/dl-machine.h b/sysdeps/s390/s390-64/dl-machine.h
+index f22db7860b4da3ec..36327c40a1972dd7 100644
+--- a/sysdeps/s390/s390-64/dl-machine.h
++++ b/sysdeps/s390/s390-64/dl-machine.h
+@@ -75,7 +75,8 @@ elf_machine_load_address (void)
+ entries will jump to the on-demand fixup code in dl-runtime.c. */
+
+ static inline int __attribute__ ((unused))
+-elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
++elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
++ int lazy, int profile)
+ {
+ extern void _dl_runtime_resolve (Elf64_Word);
+ extern void _dl_runtime_profile (Elf64_Word);
+@@ -270,8 +271,9 @@ elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
+
+ auto inline void
+ __attribute__ ((always_inline))
+-elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
+- const Elf64_Sym *sym, const struct r_found_version *version,
++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
++ const Elf64_Rela *reloc, const Elf64_Sym *sym,
++ const struct r_found_version *version,
+ void *const reloc_addr_arg, int skip_ifunc)
+ {
+ Elf64_Addr *const reloc_addr = reloc_addr_arg;
+@@ -304,7 +306,8 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
+ /* Only needed for R_390_COPY below. */
+ const Elf64_Sym *const refsym = sym;
+ #endif
+- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
++ r_type);
+ Elf64_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
+
+ if (sym != NULL
+@@ -449,7 +452,7 @@ elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
+
+ auto inline void
+ __attribute__ ((always_inline))
+-elf_machine_lazy_rel (struct link_map *map,
++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
+ Elf64_Addr l_addr, const Elf64_Rela *reloc,
+ int skip_ifunc)
+ {
+diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
+index b94d3b39ec1dca64..5262aa69c06aa8db 100644
+--- a/sysdeps/x86_64/dl-machine.h
++++ b/sysdeps/x86_64/dl-machine.h
+@@ -62,7 +62,8 @@ elf_machine_load_address (void)
+ entries will jump to the on-demand fixup code in dl-runtime.c. */
+
+ static inline int __attribute__ ((unused, always_inline))
+-elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
++elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
++ int lazy, int profile)
+ {
+ Elf64_Addr *got;
+ extern void _dl_runtime_resolve_fxsave (ElfW(Word)) attribute_hidden;
+@@ -260,8 +261,9 @@ elf_machine_plt_value (struct link_map *map, const ElfW(Rela) *reloc,
+
+ auto inline void
+ __attribute__ ((always_inline))
+-elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
+- const ElfW(Sym) *sym, const struct r_found_version *version,
++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
++ const ElfW(Rela) *reloc, const ElfW(Sym) *sym,
++ const struct r_found_version *version,
+ void *const reloc_addr_arg, int skip_ifunc)
+ {
+ ElfW(Addr) *const reloc_addr = reloc_addr_arg;
+@@ -300,7 +302,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
+ # ifndef RTLD_BOOTSTRAP
+ const ElfW(Sym) *const refsym = sym;
+ # endif
+- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, r_type);
+ ElfW(Addr) value = SYMBOL_ADDRESS (sym_map, sym, true);
+
+ if (sym != NULL
+@@ -539,7 +541,7 @@ elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+
+ auto inline void
+ __attribute ((always_inline))
+-elf_machine_lazy_rel (struct link_map *map,
++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
+ ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+ int skip_ifunc)
+ {
+@@ -573,7 +575,7 @@ elf_machine_lazy_rel (struct link_map *map,
+
+ /* Always initialize TLS descriptors completely at load time, in
+ case static TLS is allocated for it that requires locking. */
+- elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc);
++ elf_machine_rela (map, scope, reloc, sym, version, reloc_addr, skip_ifunc);
+ }
+ else if (__glibc_unlikely (r_type == R_X86_64_IRELATIVE))
+ {
diff --git a/glibc-rh2047981-13.patch b/glibc-rh2047981-13.patch
new file mode 100644
index 0000000000000000000000000000000000000000..d67e40f55952fe93c306ba0b212e0a06aa9153ed
--- /dev/null
+++ b/glibc-rh2047981-13.patch
@@ -0,0 +1,65 @@
+commit 54816ae98d57930b7c945f17485714a5574bfe47
+Author: Adhemerval Zanella
+Date: Thu Jul 29 11:13:57 2021 -0300
+
+ elf: Move LAV_CURRENT to link_lavcurrent.h
+
+ No functional change.
+
+diff --git a/bits/link_lavcurrent.h b/bits/link_lavcurrent.h
+new file mode 100644
+index 0000000000000000..44fbea1e8060997f
+--- /dev/null
++++ b/bits/link_lavcurrent.h
+@@ -0,0 +1,25 @@
++/* Data structure for communication from the run-time dynamic linker for
++ loaded ELF shared objects. LAV_CURRENT definition.
++ Copyright (C) 2021 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
++ . */
++
++#ifndef _LINK_H
++# error "Never include directly; use instead."
++#endif
++
++/* Version numbers for la_version handshake interface. */
++#define LAV_CURRENT 1
+diff --git a/elf/Makefile b/elf/Makefile
+index 6262a4a65cfd2148..b9751e8bd87c4f71 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -21,7 +21,7 @@ subdir := elf
+
+ include ../Makeconfig
+
+-headers = elf.h bits/elfclass.h link.h bits/link.h
++headers = elf.h bits/elfclass.h link.h bits/link.h bits/link_lavcurrent.h
+ routines = $(all-dl-routines) dl-support dl-iteratephdr \
+ dl-addr dl-addr-obj enbl-secure dl-profstub \
+ dl-origin dl-libc dl-sym dl-sysdep dl-error \
+diff --git a/elf/link.h b/elf/link.h
+index c67a50dd8ee9187e..cbda60b4135997f6 100644
+--- a/elf/link.h
++++ b/elf/link.h
+@@ -96,7 +96,7 @@ struct link_map
+ #ifdef __USE_GNU
+
+ /* Version numbers for la_version handshake interface. */
+-#define LAV_CURRENT 1
++#include
+
+ /* Activity types signaled through la_activity. */
+ enum
diff --git a/glibc-rh2047981-14.patch b/glibc-rh2047981-14.patch
new file mode 100644
index 0000000000000000000000000000000000000000..1d1295c178bf8c226a1711ab415d18fba22b76c4
--- /dev/null
+++ b/glibc-rh2047981-14.patch
@@ -0,0 +1,388 @@
+Added $(objpfx)tst-audit18: $(libdl) in elf/Makefile since
+we still have $(libdl) in RHEL8.
+
+commit ed3ce71f5c64c5f07cbde0ef03554ea8950d8f2c
+Author: Adhemerval Zanella
+Date: Thu Nov 11 09:28:21 2021 -0300
+
+ elf: Move la_activity (LA_ACT_ADD) after _dl_add_to_namespace_list() (BZ #28062)
+
+ It ensures that the the namespace is guaranteed to not be empty.
+
+ Checked on x86_64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+Conflicts:
+ elf/Makefile
+ elf/dl-load.c
+ Conflict with missing MAP_ANON removal.
+
+diff --git a/elf/Makefile b/elf/Makefile
+index b9751e8bd87c4f71..2312184692433313 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -219,6 +219,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ tst-dlmopen-dlerror \
+ tst-dlmopen-gethostbyname \
+ tst-audit17 \
++ tst-audit18 \
+ # reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+ neededtest neededtest2 neededtest3 neededtest4 \
+@@ -354,6 +355,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ libmarkermod5-5 tst-tls20mod-bad tst-tls21mod \
+ tst-dlmopen-dlerror-mod \
+ tst-dlmopen-gethostbyname-mod \
++ tst-auditmod18 \
++ tst-audit18mod \
+
+ # Most modules build with _ISOMAC defined, but those filtered out
+ # depend on internal headers.
+@@ -1539,6 +1542,11 @@ $(objpfx)tst-auditmod17.so: $(objpfx)tst-auditmod17.os
+ CFLAGS-.os += $(call elide-stack-protector,.os,tst-auditmod17)
+ tst-audit17-ENV = LD_AUDIT=$(objpfx)tst-auditmod17.so
+
++$(objpfx)tst-audit18: $(libdl)
++$(objpfx)tst-audit18.out: $(objpfx)tst-auditmod18.so \
++ $(objpfx)tst-audit18mod.so
++tst-audit18-ARGS = -- $(host-test-program-cmd)
++
+ # tst-sonamemove links against an older implementation of the library.
+ LDFLAGS-tst-sonamemove-linkmod1.so = \
+ -Wl,--version-script=tst-sonamemove-linkmod1.map \
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index 303e6594f9af9b7e..de5aef5777045da5 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -978,42 +978,6 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
+ }
+ #endif
+
+- /* Signal that we are going to add new objects. */
+- if (r->r_state == RT_CONSISTENT)
+- {
+-#ifdef SHARED
+- /* Auditing checkpoint: we are going to add new objects. */
+- if ((mode & __RTLD_AUDIT) == 0
+- && __glibc_unlikely (GLRO(dl_naudit) > 0))
+- {
+- struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
+- /* Do not call the functions for any auditing object. */
+- if (head->l_auditing == 0)
+- {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->activity != NULL)
+- afct->activity (&link_map_audit_state (head, cnt)->cookie,
+- LA_ACT_ADD);
+-
+- afct = afct->next;
+- }
+- }
+- }
+-#endif
+-
+- /* Notify the debugger we have added some objects. We need to
+- call _dl_debug_initialize in a static program in case dynamic
+- linking has not been used before. */
+- r->r_state = RT_ADD;
+- _dl_debug_state ();
+- LIBC_PROBE (map_start, 2, nsid, r);
+- make_consistent = true;
+- }
+- else
+- assert (r->r_state == RT_ADD);
+-
+ /* Enter the new object in the list of loaded objects. */
+ l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
+ if (__glibc_unlikely (l == NULL))
+@@ -1432,6 +1396,44 @@ cannot enable executable stack as shared object requires");
+ /* Now that the object is fully initialized add it to the object list. */
+ _dl_add_to_namespace_list (l, nsid);
+
++ /* Signal that we are going to add new objects. */
++ if (r->r_state == RT_CONSISTENT)
++ {
++#ifdef SHARED
++ /* Auditing checkpoint: we are going to add new objects. Since this
++ is called after _dl_add_to_namespace_list the namespace is guaranteed
++ to not be empty. */
++ if ((mode & __RTLD_AUDIT) == 0
++ && __glibc_unlikely (GLRO(dl_naudit) > 0))
++ {
++ struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
++ /* Do not call the functions for any auditing object. */
++ if (head->l_auditing == 0)
++ {
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ if (afct->activity != NULL)
++ afct->activity (&link_map_audit_state (head, cnt)->cookie,
++ LA_ACT_ADD);
++
++ afct = afct->next;
++ }
++ }
++ }
++#endif
++
++ /* Notify the debugger we have added some objects. We need to
++ call _dl_debug_initialize in a static program in case dynamic
++ linking has not been used before. */
++ r->r_state = RT_ADD;
++ _dl_debug_state ();
++ LIBC_PROBE (map_start, 2, nsid, r);
++ make_consistent = true;
++ }
++ else
++ assert (r->r_state == RT_ADD);
++
+ #ifdef SHARED
+ /* Auditing checkpoint: we have a new object. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0)
+diff --git a/elf/tst-audit18.c b/elf/tst-audit18.c
+new file mode 100644
+index 0000000000000000..ef784908f60d50aa
+--- /dev/null
++++ b/elf/tst-audit18.c
+@@ -0,0 +1,129 @@
++/* Check DT_AUDIT with dlmopen.
++ Copyright (C) 2021 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
++ . */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++static int restart;
++#define CMDLINE_OPTIONS \
++ { "restart", no_argument, &restart, 1 },
++
++static int
++handle_restart (void)
++{
++ {
++ void *h = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
++
++ pid_t (*s) (void) = xdlsym (h, "getpid");
++ TEST_COMPARE (s (), getpid ());
++
++ xdlclose (h);
++ }
++
++ {
++ void *h = xdlmopen (LM_ID_NEWLM, "tst-audit18mod.so", RTLD_NOW);
++
++ int (*foo) (void) = xdlsym (h, "foo");
++ TEST_COMPARE (foo (), 10);
++
++ xdlclose (h);
++ }
++
++ return 0;
++}
++
++static int
++do_test (int argc, char *argv[])
++{
++ /* We must have either:
++ - One our fource parameters left if called initially:
++ + path to ld.so optional
++ + "--library-path" optional
++ + the library path optional
++ + the application name */
++
++ if (restart)
++ return handle_restart ();
++
++ char *spargv[9];
++ int i = 0;
++ for (; i < argc - 1; i++)
++ spargv[i] = argv[i + 1];
++ spargv[i++] = (char *) "--direct";
++ spargv[i++] = (char *) "--restart";
++ spargv[i] = NULL;
++
++ setenv ("LD_AUDIT", "tst-auditmod18.so", 0);
++ struct support_capture_subprocess result
++ = support_capture_subprogram (spargv[0], spargv);
++ support_capture_subprocess_check (&result, "tst-audit18", 0, sc_allow_stderr);
++
++ struct
++ {
++ const char *name;
++ bool found;
++ } audit_iface[] =
++ {
++ { "la_version", false },
++ { "la_objsearch", false },
++ { "la_activity", false },
++ { "la_objopen", false },
++ { "la_objclose", false },
++ { "la_preinit", false },
++#if __WORDSIZE == 32
++ { "la_symbind32", false },
++#elif __WORDSIZE == 64
++ { "la_symbind64", false },
++#endif
++ };
++
++ /* Some hooks are called more than once but the test only check if any
++ is called at least once. */
++ FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
++ TEST_VERIFY (out != NULL);
++ char *buffer = NULL;
++ size_t buffer_length = 0;
++ while (xgetline (&buffer, &buffer_length, out))
++ {
++ for (int i = 0; i < array_length (audit_iface); i++)
++ if (strncmp (buffer, audit_iface[i].name,
++ strlen (audit_iface[i].name)) == 0)
++ audit_iface[i].found = true;
++ }
++ free (buffer);
++ xfclose (out);
++
++ for (int i = 0; i < array_length (audit_iface); i++)
++ TEST_COMPARE (audit_iface[i].found, true);
++
++ support_capture_subprocess_free (&result);
++
++ return 0;
++}
++
++#define TEST_FUNCTION_ARGV do_test
++#include
+diff --git a/elf/tst-audit18mod.c b/elf/tst-audit18mod.c
+new file mode 100644
+index 0000000000000000..096a9167c9f8353f
+--- /dev/null
++++ b/elf/tst-audit18mod.c
+@@ -0,0 +1,23 @@
++/* Check DT_AUDIT with dlmopen.
++ Copyright (C) 2021 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
++ . */
++
++int
++foo (void)
++{
++ return 10;
++}
+diff --git a/elf/tst-auditmod18.c b/elf/tst-auditmod18.c
+new file mode 100644
+index 0000000000000000..182992e9fdb1620c
+--- /dev/null
++++ b/elf/tst-auditmod18.c
+@@ -0,0 +1,73 @@
++/* Check DT_AUDIT with dlmopen.
++ Copyright (C) 2021 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
++ . */
++
++#include
++#include
++
++unsigned int
++la_version (unsigned int version)
++{
++ fprintf (stderr, "%s\n", __func__);
++ return LAV_CURRENT;
++}
++
++char *
++la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag)
++{
++ fprintf (stderr, "%s\n", __func__);
++ return (char *) name;
++}
++
++void
++la_activity (uintptr_t *cookie, unsigned int flag)
++{
++ fprintf (stderr, "%s\n", __func__);
++}
++
++unsigned int
++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
++{
++ fprintf (stderr, "%s\n", __func__);
++ return LA_FLG_BINDTO | LA_FLG_BINDFROM;
++}
++
++unsigned int
++la_objclose (uintptr_t *cookie)
++{
++ fprintf (stderr, "%s\n", __func__);
++ return 0;
++}
++
++void
++la_preinit (uintptr_t *cookie)
++{
++ fprintf (stderr, "%s\n", __func__);
++}
++
++uintptr_t
++#if __ELF_NATIVE_CLASS == 32
++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
++ uintptr_t *defcook, unsigned int *flags, const char *symname)
++#else
++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
++ uintptr_t *defcook, unsigned int *flags, const char *symname)
++#endif
++{
++ fprintf (stderr, "%s\n", __func__);
++ return sym->st_value;
++}
diff --git a/glibc-rh2047981-15.patch b/glibc-rh2047981-15.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7da5392ebc42c882de643341ef9f7df481238c7d
--- /dev/null
+++ b/glibc-rh2047981-15.patch
@@ -0,0 +1,160 @@
+commit aee6e90f93e285016b6cd9c8bd00402c19ba271b
+Author: Adhemerval Zanella
+Date: Mon Jul 19 15:47:51 2021 -0300
+
+ elf: Add _dl_audit_objopen
+
+ It consolidates the code required to call la_objopen audit callback.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+Conflicts:
+ elf/Makefile
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 2312184692433313..08a32a712a34f2cc 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -64,7 +64,8 @@ elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \
+ # interpreter and operating independent of libc.
+ rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \
+ dl-error-minimal dl-conflict dl-hwcaps dl-hwcaps_split dl-hwcaps-subdirs \
+- dl-usage dl-diagnostics dl-diagnostics-kernel dl-diagnostics-cpu
++ dl-usage dl-diagnostics dl-diagnostics-kernel dl-diagnostics-cpu \
++ dl-audit
+ all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines)
+
+ CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables
+diff --git a/elf/dl-audit.c b/elf/dl-audit.c
+new file mode 100644
+index 0000000000000000..4066dfe85146b9d4
+--- /dev/null
++++ b/elf/dl-audit.c
+@@ -0,0 +1,39 @@
++/* Audit common functions.
++ Copyright (C) 2021 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
++ . */
++
++#include
++
++void
++_dl_audit_objopen (struct link_map *l, Lmid_t nsid)
++{
++ if (__glibc_likely (GLRO(dl_naudit) == 0))
++ return;
++
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ if (afct->objopen != NULL)
++ {
++ struct auditstate *state = link_map_audit_state (l, cnt);
++ state->bindflags = afct->objopen (l, nsid, &state->cookie);
++ l->l_audit_any_plt |= state->bindflags != 0;
++ }
++
++ afct = afct->next;
++ }
++}
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index de5aef5777045da5..c11b1d1781e9b40b 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -1436,22 +1436,8 @@ cannot enable executable stack as shared object requires");
+
+ #ifdef SHARED
+ /* Auditing checkpoint: we have a new object. */
+- if (__glibc_unlikely (GLRO(dl_naudit) > 0)
+- && !GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
+- {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->objopen != NULL)
+- {
+- struct auditstate *state = link_map_audit_state (l, cnt);
+- state->bindflags = afct->objopen (l, nsid, &state->cookie);
+- l->l_audit_any_plt |= state->bindflags != 0;
+- }
+-
+- afct = afct->next;
+- }
+- }
++ if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
++ _dl_audit_objopen (l, nsid);
+ #endif
+
+ return l;
+diff --git a/elf/rtld.c b/elf/rtld.c
+index f3836b8a78faaf27..1982e42390760e0a 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -1075,25 +1075,6 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
+ dlmargs.map->l_auditing = 1;
+ }
+
+-/* Notify the the audit modules that the object MAP has already been
+- loaded. */
+-static void
+-notify_audit_modules_of_loaded_object (struct link_map *map)
+-{
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->objopen != NULL)
+- {
+- struct auditstate *state = link_map_audit_state (map, cnt);
+- state->bindflags = afct->objopen (map, LM_ID_BASE, &state->cookie);
+- map->l_audit_any_plt |= state->bindflags != 0;
+- }
+-
+- afct = afct->next;
+- }
+-}
+-
+ /* Load all audit modules. */
+ static void
+ load_audit_modules (struct link_map *main_map, struct audit_list *audit_list)
+@@ -1112,8 +1093,8 @@ load_audit_modules (struct link_map *main_map, struct audit_list *audit_list)
+ program and the dynamic linker itself). */
+ if (GLRO(dl_naudit) > 0)
+ {
+- notify_audit_modules_of_loaded_object (main_map);
+- notify_audit_modules_of_loaded_object (&GL(dl_rtld_map));
++ _dl_audit_objopen (main_map, LM_ID_BASE);
++ _dl_audit_objopen (&GL(dl_rtld_map), LM_ID_BASE);
+ }
+ }
+
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 2dd6f0c3c4aaaef5..410f070e28b74bdf 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -1268,6 +1268,11 @@ link_map_audit_state (struct link_map *l, size_t index)
+ {
+ return &l->l_audit[index];
+ }
++
++/* Call the la_objopen from the audit modules for the link_map L on the
++ namespace identification NSID. */
++void _dl_audit_objopen (struct link_map *l, Lmid_t nsid)
++ attribute_hidden;
+ #endif /* SHARED */
+
+ __END_DECLS
diff --git a/glibc-rh2047981-16.patch b/glibc-rh2047981-16.patch
new file mode 100644
index 0000000000000000000000000000000000000000..eec1516b2b2790b16616b5c270ae4a3f959f35d7
--- /dev/null
+++ b/glibc-rh2047981-16.patch
@@ -0,0 +1,253 @@
+commit 3dac3959a5cb585b065cef2cb8a8d909c907e202
+Author: Adhemerval Zanella
+Date: Tue Jul 20 11:03:34 2021 -0300
+
+ elf: Add _dl_audit_activity_map and _dl_audit_activity_nsid
+
+ It consolidates the code required to call la_activity audit
+ callback.
+
+ Also for a new Lmid_t the namespace link_map list are empty, so it
+ requires to check if before using it. This can happen for when audit
+ module is used along with dlmopen.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+diff --git a/elf/dl-audit.c b/elf/dl-audit.c
+index 4066dfe85146b9d4..74b87f4b39be75e1 100644
+--- a/elf/dl-audit.c
++++ b/elf/dl-audit.c
+@@ -18,6 +18,32 @@
+
+ #include
+
++void
++_dl_audit_activity_map (struct link_map *l, int action)
++{
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ if (afct->activity != NULL)
++ afct->activity (&link_map_audit_state (l, cnt)->cookie, action);
++ afct = afct->next;
++ }
++}
++
++void
++_dl_audit_activity_nsid (Lmid_t nsid, int action)
++{
++ /* If head is NULL, the namespace has become empty, and the audit interface
++ does not give us a way to signal LA_ACT_CONSISTENT for it because the
++ first loaded module is used to identify the namespace. */
++ struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
++ if (__glibc_likely (GLRO(dl_naudit) == 0)
++ || head == NULL || head->l_auditing)
++ return;
++
++ _dl_audit_activity_map (head, action);
++}
++
+ void
+ _dl_audit_objopen (struct link_map *l, Lmid_t nsid)
+ {
+diff --git a/elf/dl-close.c b/elf/dl-close.c
+index 698bda929c0eab6c..1ba594b600c4c87a 100644
+--- a/elf/dl-close.c
++++ b/elf/dl-close.c
+@@ -478,25 +478,7 @@ _dl_close_worker (struct link_map *map, bool force)
+
+ #ifdef SHARED
+ /* Auditing checkpoint: we will start deleting objects. */
+- if (__glibc_unlikely (do_audit))
+- {
+- struct link_map *head = ns->_ns_loaded;
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- /* Do not call the functions for any auditing object. */
+- if (head->l_auditing == 0)
+- {
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->activity != NULL)
+- {
+- struct auditstate *state = link_map_audit_state (head, cnt);
+- afct->activity (&state->cookie, LA_ACT_DELETE);
+- }
+-
+- afct = afct->next;
+- }
+- }
+- }
++ _dl_audit_activity_nsid (nsid, LA_ACT_DELETE);
+ #endif
+
+ /* Notify the debugger we are about to remove some loaded objects. */
+@@ -791,32 +773,9 @@ _dl_close_worker (struct link_map *map, bool force)
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+
+ #ifdef SHARED
+- /* Auditing checkpoint: we have deleted all objects. */
+- if (__glibc_unlikely (do_audit))
+- {
+- struct link_map *head = ns->_ns_loaded;
+- /* If head is NULL, the namespace has become empty, and the
+- audit interface does not give us a way to signal
+- LA_ACT_CONSISTENT for it because the first loaded module is
+- used to identify the namespace.
+-
+- Furthermore, do not notify auditors of the cleanup of a
+- failed audit module loading attempt. */
+- if (head != NULL && head->l_auditing == 0)
+- {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->activity != NULL)
+- {
+- struct auditstate *state = link_map_audit_state (head, cnt);
+- afct->activity (&state->cookie, LA_ACT_CONSISTENT);
+- }
+-
+- afct = afct->next;
+- }
+- }
+- }
++ /* Auditing checkpoint: we have deleted all objects. Also, do not notify
++ auditors of the cleanup of a failed audit module loading attempt. */
++ _dl_audit_activity_nsid (nsid, LA_ACT_CONSISTENT);
+ #endif
+
+ if (__builtin_expect (ns->_ns_loaded == NULL, 0)
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index c11b1d1781e9b40b..8a18c761bb753e37 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -1403,24 +1403,8 @@ cannot enable executable stack as shared object requires");
+ /* Auditing checkpoint: we are going to add new objects. Since this
+ is called after _dl_add_to_namespace_list the namespace is guaranteed
+ to not be empty. */
+- if ((mode & __RTLD_AUDIT) == 0
+- && __glibc_unlikely (GLRO(dl_naudit) > 0))
+- {
+- struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
+- /* Do not call the functions for any auditing object. */
+- if (head->l_auditing == 0)
+- {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->activity != NULL)
+- afct->activity (&link_map_audit_state (head, cnt)->cookie,
+- LA_ACT_ADD);
+-
+- afct = afct->next;
+- }
+- }
+- }
++ if ((mode & __RTLD_AUDIT) == 0)
++ _dl_audit_activity_nsid (nsid, LA_ACT_ADD);
+ #endif
+
+ /* Notify the debugger we have added some objects. We need to
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index b5a4da04907d8d29..660a56b2fb2639cd 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -598,25 +598,7 @@ dl_open_worker_begin (void *a)
+
+ #ifdef SHARED
+ /* Auditing checkpoint: we have added all objects. */
+- if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+- {
+- struct link_map *head = GL(dl_ns)[new->l_ns]._ns_loaded;
+- /* Do not call the functions for any auditing object. */
+- if (head->l_auditing == 0)
+- {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->activity != NULL)
+- {
+- struct auditstate *state = link_map_audit_state (head, cnt);
+- afct->activity (&state->cookie, LA_ACT_CONSISTENT);
+- }
+-
+- afct = afct->next;
+- }
+- }
+- }
++ _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
+ #endif
+
+ /* Notify the debugger all new objects are now ready to go. */
+diff --git a/elf/rtld.c b/elf/rtld.c
+index 1982e42390760e0a..767acd122262b824 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -1799,18 +1799,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
+
+ /* Auditing checkpoint: we are ready to signal that the initial map
+ is being constructed. */
+- if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+- {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->activity != NULL)
+- afct->activity (&link_map_audit_state (main_map, cnt)->cookie,
+- LA_ACT_ADD);
+-
+- afct = afct->next;
+- }
+- }
++ _dl_audit_activity_map (main_map, LA_ACT_ADD);
+
+ /* We have two ways to specify objects to preload: via environment
+ variable and via the file /etc/ld.so.preload. The latter can also
+@@ -2484,23 +2473,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
+
+ #ifdef SHARED
+ /* Auditing checkpoint: we have added all objects. */
+- if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+- {
+- struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+- /* Do not call the functions for any auditing object. */
+- if (head->l_auditing == 0)
+- {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->activity != NULL)
+- afct->activity (&link_map_audit_state (head, cnt)->cookie,
+- LA_ACT_CONSISTENT);
+-
+- afct = afct->next;
+- }
+- }
+- }
++ _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
+ #endif
+
+ /* Notify the debugger all new objects are now ready to go. We must re-get
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 410f070e28b74bdf..05737342d6287233 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -1269,6 +1269,16 @@ link_map_audit_state (struct link_map *l, size_t index)
+ return &l->l_audit[index];
+ }
+
++/* Call the la_activity from the audit modules from the link map L and issues
++ the ACTION argument. */
++void _dl_audit_activity_map (struct link_map *l, int action)
++ attribute_hidden;
++
++/* Call the la_activity from the audit modules from the link map from the
++ namespace NSID and issues the ACTION argument. */
++void _dl_audit_activity_nsid (Lmid_t nsid, int action)
++ attribute_hidden;
++
+ /* Call the la_objopen from the audit modules for the link_map L on the
+ namespace identification NSID. */
+ void _dl_audit_objopen (struct link_map *l, Lmid_t nsid)
diff --git a/glibc-rh2047981-17.patch b/glibc-rh2047981-17.patch
new file mode 100644
index 0000000000000000000000000000000000000000..4a22e82df25a262ec97e6d685894c4dd2f6896e6
--- /dev/null
+++ b/glibc-rh2047981-17.patch
@@ -0,0 +1,156 @@
+commit c91008d3490e4e3ce29520068405f081f0d368ca
+Author: Adhemerval Zanella
+Date: Tue Jul 20 13:47:36 2021 -0300
+
+ elf: Add _dl_audit_objsearch
+
+ It consolidates the code required to call la_objsearch audit
+ callback.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+diff --git a/elf/dl-audit.c b/elf/dl-audit.c
+index 74b87f4b39be75e1..5682427220569d90 100644
+--- a/elf/dl-audit.c
++++ b/elf/dl-audit.c
+@@ -44,6 +44,28 @@ _dl_audit_activity_nsid (Lmid_t nsid, int action)
+ _dl_audit_activity_map (head, action);
+ }
+
++const char *
++_dl_audit_objsearch (const char *name, struct link_map *l, unsigned int code)
++{
++ if (l == NULL || l->l_auditing || code == 0)
++ return name;
++
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ if (afct->objsearch != NULL)
++ {
++ struct auditstate *state = link_map_audit_state (l, cnt);
++ name = afct->objsearch (name, &state->cookie, code);
++ if (name == NULL)
++ return NULL;
++ }
++ afct = afct->next;
++ }
++
++ return name;
++}
++
+ void
+ _dl_audit_objopen (struct link_map *l, Lmid_t nsid)
+ {
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index 8a18c761bb753e37..1613217a236c7fc3 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -1517,32 +1517,20 @@ open_verify (const char *name, int fd,
+
+ #ifdef SHARED
+ /* Give the auditing libraries a chance. */
+- if (__glibc_unlikely (GLRO(dl_naudit) > 0) && whatcode != 0
+- && loader->l_auditing == 0)
++ if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+ const char *original_name = name;
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->objsearch != NULL)
+- {
+- struct auditstate *state = link_map_audit_state (loader, cnt);
+- name = afct->objsearch (name, &state->cookie, whatcode);
+- if (name == NULL)
+- /* Ignore the path. */
+- return -1;
+- }
+-
+- afct = afct->next;
+- }
++ name = _dl_audit_objsearch (name, loader, whatcode);
++ if (name == NULL)
++ return -1;
+
+ if (fd != -1 && name != original_name && strcmp (name, original_name))
+- {
+- /* An audit library changed what we're supposed to open,
+- so FD no longer matches it. */
+- __close_nocancel (fd);
+- fd = -1;
+- }
++ {
++ /* An audit library changed what we're supposed to open,
++ so FD no longer matches it. */
++ __close_nocancel (fd);
++ fd = -1;
++ }
+ }
+ #endif
+
+@@ -1992,36 +1980,17 @@ _dl_map_object (struct link_map *loader, const char *name,
+ #ifdef SHARED
+ /* Give the auditing libraries a chance to change the name before we
+ try anything. */
+- if (__glibc_unlikely (GLRO(dl_naudit) > 0)
+- && (loader == NULL || loader->l_auditing == 0))
++ if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ const char *before = name;
++ name = _dl_audit_objsearch (name, loader, LA_SER_ORIG);
++ if (name == NULL)
+ {
+- if (afct->objsearch != NULL)
+- {
+- const char *before = name;
+- struct auditstate *state = link_map_audit_state (loader, cnt);
+- name = afct->objsearch (name, &state->cookie, LA_SER_ORIG);
+- if (name == NULL)
+- {
+- /* Do not try anything further. */
+- fd = -1;
+- goto no_file;
+- }
+- if (before != name && strcmp (before, name) != 0)
+- {
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+- _dl_debug_printf ("audit changed filename %s -> %s\n",
+- before, name);
+-
+- if (origname == NULL)
+- origname = before;
+- }
+- }
+-
+- afct = afct->next;
++ fd = -1;
++ goto no_file;
+ }
++ if (before != name && strcmp (before, name) != 0)
++ origname = before;
+ }
+ #endif
+
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 05737342d6287233..da83e717e8cd8e0b 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -1269,6 +1269,13 @@ link_map_audit_state (struct link_map *l, size_t index)
+ return &l->l_audit[index];
+ }
+
++/* Call the la_objsearch from the audit modules from the link map L. If
++ ORIGNAME is non NULL, it is updated with the revious name prior calling
++ la_objsearch. */
++const char *_dl_audit_objsearch (const char *name, struct link_map *l,
++ unsigned int code)
++ attribute_hidden;
++
+ /* Call the la_activity from the audit modules from the link map L and issues
+ the ACTION argument. */
+ void _dl_audit_activity_map (struct link_map *l, int action)
diff --git a/glibc-rh2047981-18.patch b/glibc-rh2047981-18.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b8662956ba9eec162ef1b304c981689118e260b8
--- /dev/null
+++ b/glibc-rh2047981-18.patch
@@ -0,0 +1,122 @@
+commit 311c9ee54ea963ff69bd3a2e6981c37e893b4c3e
+Author: Adhemerval Zanella
+Date: Tue Jul 20 14:04:51 2021 -0300
+
+ elf: Add _dl_audit_objclose
+
+ It consolidates the code required to call la_objclose audit
+ callback.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+diff --git a/elf/dl-audit.c b/elf/dl-audit.c
+index 5682427220569d90..cb1c3de93cba447b 100644
+--- a/elf/dl-audit.c
++++ b/elf/dl-audit.c
+@@ -85,3 +85,24 @@ _dl_audit_objopen (struct link_map *l, Lmid_t nsid)
+ afct = afct->next;
+ }
+ }
++
++void
++_dl_audit_objclose (struct link_map *l)
++{
++ if (__glibc_likely (GLRO(dl_naudit) == 0)
++ || GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
++ return;
++
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ if (afct->objclose != NULL)
++ {
++ struct auditstate *state= link_map_audit_state (l, cnt);
++ /* Return value is ignored. */
++ afct->objclose (&state->cookie);
++ }
++
++ afct = afct->next;
++ }
++}
+diff --git a/elf/dl-close.c b/elf/dl-close.c
+index 1ba594b600c4c87a..74ca9a85dd309780 100644
+--- a/elf/dl-close.c
++++ b/elf/dl-close.c
+@@ -266,9 +266,6 @@ _dl_close_worker (struct link_map *map, bool force)
+ used + (nsid == LM_ID_BASE), true);
+
+ /* Call all termination functions at once. */
+-#ifdef SHARED
+- bool do_audit = GLRO(dl_naudit) > 0 && !ns->_ns_loaded->l_auditing;
+-#endif
+ bool unload_any = false;
+ bool scope_mem_left = false;
+ unsigned int unload_global = 0;
+@@ -302,22 +299,7 @@ _dl_close_worker (struct link_map *map, bool force)
+
+ #ifdef SHARED
+ /* Auditing checkpoint: we remove an object. */
+- if (__glibc_unlikely (do_audit))
+- {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->objclose != NULL)
+- {
+- struct auditstate *state
+- = link_map_audit_state (imap, cnt);
+- /* Return value is ignored. */
+- (void) afct->objclose (&state->cookie);
+- }
+-
+- afct = afct->next;
+- }
+- }
++ _dl_audit_objclose (imap);
+ #endif
+
+ /* This object must not be used anymore. */
+diff --git a/elf/dl-fini.c b/elf/dl-fini.c
+index 915ceb104e1c81d6..e102d93647cb8c47 100644
+--- a/elf/dl-fini.c
++++ b/elf/dl-fini.c
+@@ -146,21 +146,7 @@ _dl_fini (void)
+
+ #ifdef SHARED
+ /* Auditing checkpoint: another object closed. */
+- if (!do_audit && __builtin_expect (GLRO(dl_naudit) > 0, 0))
+- {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->objclose != NULL)
+- {
+- struct auditstate *state
+- = link_map_audit_state (l, cnt);
+- /* Return value is ignored. */
+- (void) afct->objclose (&state->cookie);
+- }
+- afct = afct->next;
+- }
+- }
++ _dl_audit_objclose (l);
+ #endif
+ }
+
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index da83e717e8cd8e0b..3db25c5be1acf871 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -1290,6 +1290,10 @@ void _dl_audit_activity_nsid (Lmid_t nsid, int action)
+ namespace identification NSID. */
+ void _dl_audit_objopen (struct link_map *l, Lmid_t nsid)
+ attribute_hidden;
++
++/* Call the la_objclose from the audit modules for the link_map L. */
++void _dl_audit_objclose (struct link_map *l)
++ attribute_hidden;
+ #endif /* SHARED */
+
+ __END_DECLS
diff --git a/glibc-rh2047981-19.patch b/glibc-rh2047981-19.patch
new file mode 100644
index 0000000000000000000000000000000000000000..2c554053ea55e61e7e1718b71d0fbc84eea97b31
--- /dev/null
+++ b/glibc-rh2047981-19.patch
@@ -0,0 +1,333 @@
+commit cda4f265c65fb6c4ce38ca1cf0a7e527c5e77cd5
+Author: Adhemerval Zanella
+Date: Tue Jul 20 15:58:35 2021 -0300
+
+ elf: Add _dl_audit_symbind_alt and _dl_audit_symbind
+
+ It consolidates the code required to call la_symbind{32,64} audit
+ callback.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+diff --git a/elf/Versions b/elf/Versions
+index be88c48e6d45a937..c5d4342cf1f5124c 100644
+--- a/elf/Versions
++++ b/elf/Versions
+@@ -59,6 +59,7 @@ ld {
+ _dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info;
+ _dl_deallocate_tls; _dl_make_stack_executable;
+ _dl_rtld_di_serinfo; _dl_starting_up; _dl_fatal_printf;
++ _dl_audit_symbind_alt;
+ _rtld_global; _rtld_global_ro;
+
+ # Only here for gdb while a better method is developed.
+diff --git a/elf/dl-audit.c b/elf/dl-audit.c
+index cb1c3de93cba447b..a21530f30bc5524b 100644
+--- a/elf/dl-audit.c
++++ b/elf/dl-audit.c
+@@ -16,6 +16,7 @@
+ License along with the GNU C Library; if not, see
+ . */
+
++#include
+ #include
+
+ void
+@@ -106,3 +107,124 @@ _dl_audit_objclose (struct link_map *l)
+ afct = afct->next;
+ }
+ }
++
++void
++_dl_audit_symbind_alt (struct link_map *l, const ElfW(Sym) *ref, void **value,
++ lookup_t result)
++{
++ if ((l->l_audit_any_plt | result->l_audit_any_plt) == 0)
++ return;
++
++ const char *strtab = (const char *) D_PTR (result, l_info[DT_STRTAB]);
++ /* Compute index of the symbol entry in the symbol table of the DSO with
++ the definition. */
++ unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result, l_info[DT_SYMTAB]));
++
++ unsigned int altvalue = 0;
++ /* Synthesize a symbol record where the st_value field is the result. */
++ ElfW(Sym) sym = *ref;
++ sym.st_value = (ElfW(Addr)) *value;
++
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ struct auditstate *match_audit = link_map_audit_state (l, cnt);
++ struct auditstate *result_audit = link_map_audit_state (result, cnt);
++ if (afct->symbind != NULL
++ && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0
++ || ((result_audit->bindflags & LA_FLG_BINDTO)
++ != 0)))
++ {
++ unsigned int flags = altvalue | LA_SYMB_DLSYM;
++ uintptr_t new_value = afct->symbind (&sym, ndx,
++ &match_audit->cookie,
++ &result_audit->cookie,
++ &flags, strtab + ref->st_name);
++ if (new_value != (uintptr_t) sym.st_value)
++ {
++ altvalue = LA_SYMB_ALTVALUE;
++ sym.st_value = new_value;
++ }
++
++ afct = afct->next;
++ }
++
++ *value = (void *) sym.st_value;
++ }
++}
++rtld_hidden_def (_dl_audit_symbind_alt)
++
++void
++_dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result,
++ const ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value,
++ lookup_t result)
++{
++ reloc_result->bound = result;
++ /* Compute index of the symbol entry in the symbol table of the DSO with the
++ definition. */
++ reloc_result->boundndx = (defsym - (ElfW(Sym) *) D_PTR (result,
++ l_info[DT_SYMTAB]));
++
++ if ((l->l_audit_any_plt | result->l_audit_any_plt) == 0)
++ {
++ /* Set all bits since this symbol binding is not interesting. */
++ reloc_result->enterexit = (1u << DL_NNS) - 1;
++ return;
++ }
++
++ /* Synthesize a symbol record where the st_value field is the result. */
++ ElfW(Sym) sym = *defsym;
++ sym.st_value = DL_FIXUP_VALUE_ADDR (*value);
++
++ /* Keep track whether there is any interest in tracing the call in the lower
++ two bits. */
++ assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8);
++ assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3);
++ reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
++
++ const char *strtab2 = (const void *) D_PTR (result, l_info[DT_STRTAB]);
++
++ unsigned int flags = 0;
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ /* XXX Check whether both DSOs must request action or only one */
++ struct auditstate *l_state = link_map_audit_state (l, cnt);
++ struct auditstate *result_state = link_map_audit_state (result, cnt);
++ if ((l_state->bindflags & LA_FLG_BINDFROM) != 0
++ && (result_state->bindflags & LA_FLG_BINDTO) != 0)
++ {
++ if (afct->symbind != NULL)
++ {
++ uintptr_t new_value = afct->symbind (&sym,
++ reloc_result->boundndx,
++ &l_state->cookie,
++ &result_state->cookie,
++ &flags,
++ strtab2 + defsym->st_name);
++ if (new_value != (uintptr_t) sym.st_value)
++ {
++ flags |= LA_SYMB_ALTVALUE;
++ sym.st_value = new_value;
++ }
++ }
++
++ /* Remember the results for every audit library and store a summary
++ in the first two bits. */
++ reloc_result->enterexit &= flags & (LA_SYMB_NOPLTENTER
++ | LA_SYMB_NOPLTEXIT);
++ reloc_result->enterexit |= ((flags & (LA_SYMB_NOPLTENTER
++ | LA_SYMB_NOPLTEXIT))
++ << ((cnt + 1) * 2));
++ }
++ else
++ /* If the bind flags say this auditor is not interested, set the bits
++ manually. */
++ reloc_result->enterexit |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
++ << ((cnt + 1) * 2));
++ afct = afct->next;
++ }
++
++ reloc_result->flags = flags;
++ *value = DL_FIXUP_ADDR_VALUE (sym.st_value);
++}
+diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
+index 4ccd7c30678fafad..d4840a7c17441126 100644
+--- a/elf/dl-runtime.c
++++ b/elf/dl-runtime.c
+@@ -296,84 +296,7 @@ _dl_profile_fixup (
+ auditing libraries the possibility to change the value and
+ tell us whether further auditing is wanted. */
+ if (defsym != NULL && GLRO(dl_naudit) > 0)
+- {
+- reloc_result->bound = result;
+- /* Compute index of the symbol entry in the symbol table of
+- the DSO with the definition. */
+- reloc_result->boundndx = (defsym
+- - (ElfW(Sym) *) D_PTR (result,
+- l_info[DT_SYMTAB]));
+-
+- /* Determine whether any of the two participating DSOs is
+- interested in auditing. */
+- if ((l->l_audit_any_plt | result->l_audit_any_plt) != 0)
+- {
+- unsigned int flags = 0;
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- /* Synthesize a symbol record where the st_value field is
+- the result. */
+- ElfW(Sym) sym = *defsym;
+- sym.st_value = DL_FIXUP_VALUE_ADDR (value);
+-
+- /* Keep track whether there is any interest in tracing
+- the call in the lower two bits. */
+- assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8);
+- assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3);
+- reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
+-
+- const char *strtab2 = (const void *) D_PTR (result,
+- l_info[DT_STRTAB]);
+-
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- /* XXX Check whether both DSOs must request action or
+- only one */
+- struct auditstate *l_state = link_map_audit_state (l, cnt);
+- struct auditstate *result_state
+- = link_map_audit_state (result, cnt);
+- if ((l_state->bindflags & LA_FLG_BINDFROM) != 0
+- && (result_state->bindflags & LA_FLG_BINDTO) != 0)
+- {
+- if (afct->symbind != NULL)
+- {
+- uintptr_t new_value
+- = afct->symbind (&sym, reloc_result->boundndx,
+- &l_state->cookie,
+- &result_state->cookie,
+- &flags,
+- strtab2 + defsym->st_name);
+- if (new_value != (uintptr_t) sym.st_value)
+- {
+- flags |= LA_SYMB_ALTVALUE;
+- sym.st_value = new_value;
+- }
+- }
+-
+- /* Remember the results for every audit library and
+- store a summary in the first two bits. */
+- reloc_result->enterexit
+- &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
+- reloc_result->enterexit
+- |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
+- << ((cnt + 1) * 2));
+- }
+- else
+- /* If the bind flags say this auditor is not interested,
+- set the bits manually. */
+- reloc_result->enterexit
+- |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
+- << ((cnt + 1) * 2));
+-
+- afct = afct->next;
+- }
+-
+- reloc_result->flags = flags;
+- value = DL_FIXUP_ADDR_VALUE (sym.st_value);
+- }
+- else
+- /* Set all bits since this symbol binding is not interesting. */
+- reloc_result->enterexit = (1u << DL_NNS) - 1;
+- }
++ _dl_audit_symbind (l, reloc_result, defsym, &value, result);
+ #endif
+
+ /* Store the result for later runs. */
+diff --git a/elf/dl-sym-post.h b/elf/dl-sym-post.h
+index 4c4f574633497789..f33934c92047f293 100644
+--- a/elf/dl-sym-post.h
++++ b/elf/dl-sym-post.h
+@@ -52,54 +52,9 @@ _dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value,
+ tell us whether further auditing is wanted. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+- const char *strtab = (const char *) D_PTR (result,
+- l_info[DT_STRTAB]);
+- /* Compute index of the symbol entry in the symbol table of
+- the DSO with the definition. */
+- unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
+- l_info[DT_SYMTAB]));
+-
+ if (match == NULL)
+ match = _dl_sym_find_caller_link_map (caller);
+-
+- if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
+- {
+- unsigned int altvalue = 0;
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- /* Synthesize a symbol record where the st_value field is
+- the result. */
+- ElfW(Sym) sym = *ref;
+- sym.st_value = (ElfW(Addr)) value;
+-
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- struct auditstate *match_audit
+- = link_map_audit_state (match, cnt);
+- struct auditstate *result_audit
+- = link_map_audit_state (result, cnt);
+- if (afct->symbind != NULL
+- && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0
+- || ((result_audit->bindflags & LA_FLG_BINDTO)
+- != 0)))
+- {
+- unsigned int flags = altvalue | LA_SYMB_DLSYM;
+- uintptr_t new_value
+- = afct->symbind (&sym, ndx,
+- &match_audit->cookie,
+- &result_audit->cookie,
+- &flags, strtab + ref->st_name);
+- if (new_value != (uintptr_t) sym.st_value)
+- {
+- altvalue = LA_SYMB_ALTVALUE;
+- sym.st_value = new_value;
+- }
+- }
+-
+- afct = afct->next;
+- }
+-
+- value = (void *) sym.st_value;
+- }
++ _dl_audit_symbind_alt (match, ref, &value, result);
+ }
+ #endif
+ return value;
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 3db25c5be1acf871..fa55c3bde10de52e 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -1294,6 +1294,16 @@ void _dl_audit_objopen (struct link_map *l, Lmid_t nsid)
+ /* Call the la_objclose from the audit modules for the link_map L. */
+ void _dl_audit_objclose (struct link_map *l)
+ attribute_hidden;
++
++/* Call the la_symbind{32,64} from the audit modules for the link_map L. */
++void _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result,
++ const ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value,
++ lookup_t result)
++ attribute_hidden;
++/* Same as _dl_audit_symbind, but also sets LA_SYMB_DLSYM flag. */
++void _dl_audit_symbind_alt (struct link_map *l, const ElfW(Sym) *ref,
++ void **value, lookup_t result);
++rtld_hidden_proto (_dl_audit_symbind_alt)
+ #endif /* SHARED */
+
+ __END_DECLS
diff --git a/glibc-rh2047981-2.patch b/glibc-rh2047981-2.patch
new file mode 100644
index 0000000000000000000000000000000000000000..02bc4039e05252d53cf7c587dfe564a25ea82205
--- /dev/null
+++ b/glibc-rh2047981-2.patch
@@ -0,0 +1,70 @@
+commit acdcca72940e060270e4e54d9c0457398110f409
+Author: John David Anglin
+Date: Mon Mar 30 21:58:06 2020 +0000
+
+ Add new file missed in previous hppa commit.
+
+diff --git a/sysdeps/hppa/dl-runtime.c b/sysdeps/hppa/dl-runtime.c
+new file mode 100644
+index 0000000000000000..885a3f1837cbc56d
+--- /dev/null
++++ b/sysdeps/hppa/dl-runtime.c
+@@ -0,0 +1,58 @@
++/* On-demand PLT fixup for shared objects. HPPA version.
++ Copyright (C) 2019 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, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* Clear PA_GP_RELOC bit in relocation offset. */
++#define reloc_offset (reloc_arg & ~PA_GP_RELOC)
++#define reloc_index (reloc_arg & ~PA_GP_RELOC) / sizeof (PLTREL)
++
++#include
++
++/* The caller has encountered a partially relocated function descriptor.
++ The gp of the descriptor has been updated, but not the ip. We find
++ the function descriptor again and compute the relocation offset and
++ return that to the caller. The caller will continue on to call
++ _dl_fixup with the relocation offset. */
++
++ElfW(Word)
++attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
++_dl_fix_reloc_arg (struct fdesc *fptr, struct link_map *l)
++{
++ Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type;
++ const Elf32_Rela *reloc;
++
++ l_addr = l->l_addr;
++ jmprel = D_PTR(l, l_info[DT_JMPREL]);
++ end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
++
++ /* Look for the entry... */
++ for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
++ {
++ reloc = (const Elf32_Rela *) iplt;
++ r_type = ELF32_R_TYPE (reloc->r_info);
++
++ if (__builtin_expect (r_type == R_PARISC_IPLT, 1)
++ && fptr == (struct fdesc *) (reloc->r_offset + l_addr))
++ /* Found entry. Return the reloc offset. */
++ return iplt - jmprel;
++ }
++
++ /* Crash if we weren't passed a valid function pointer. */
++ ABORT_INSTRUCTION;
++ return 0;
++}
diff --git a/glibc-rh2047981-20.patch b/glibc-rh2047981-20.patch
new file mode 100644
index 0000000000000000000000000000000000000000..bce1f3dd00c225d57bb9f3a7aecc44a44594c0e0
--- /dev/null
+++ b/glibc-rh2047981-20.patch
@@ -0,0 +1,113 @@
+commit 0b98a8748759e88b58927882a8714109abe0a2d6
+Author: Adhemerval Zanella
+Date: Thu Jul 22 17:10:57 2021 -0300
+
+ elf: Add _dl_audit_preinit
+
+ It consolidates the code required to call la_preinit audit
+ callback.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+Conflicts:
+ csu/libc-start.c
+ Rework to existing init call code.
+
+diff --git a/csu/libc-start.c b/csu/libc-start.c
+index fd0f8640eaeae34c..ae703cfa620163fd 100644
+--- a/csu/libc-start.c
++++ b/csu/libc-start.c
+@@ -265,32 +265,20 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
+ #ifdef SHARED
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
+ GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
+-#endif
++
+ if (init)
+ (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
+
+-#ifdef SHARED
+ /* Auditing checkpoint: we have a new object. */
+- if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+- {
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->preinit != NULL)
+- afct->preinit (&link_map_audit_state (head, cnt)->cookie);
+-
+- afct = afct->next;
+- }
+- }
+-#endif
++ _dl_audit_preinit (GL(dl_ns)[LM_ID_BASE]._ns_loaded);
+
+-#ifdef SHARED
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
+ GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
+-#endif
+
+-#ifndef SHARED
++#else /* !SHARED */
++ if (init)
++ (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
++
+ _dl_debug_initialize (0, LM_ID_BASE);
+ #endif
+ #ifdef HAVE_CLEANUP_JMP_BUF
+diff --git a/elf/Versions b/elf/Versions
+index c5d4342cf1f5124c..35ac181bdb099af8 100644
+--- a/elf/Versions
++++ b/elf/Versions
+@@ -59,7 +59,7 @@ ld {
+ _dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info;
+ _dl_deallocate_tls; _dl_make_stack_executable;
+ _dl_rtld_di_serinfo; _dl_starting_up; _dl_fatal_printf;
+- _dl_audit_symbind_alt;
++ _dl_audit_symbind_alt; _dl_audit_preinit;
+ _rtld_global; _rtld_global_ro;
+
+ # Only here for gdb while a better method is developed.
+diff --git a/elf/dl-audit.c b/elf/dl-audit.c
+index a21530f30bc5524b..0b6fac8e48877c93 100644
+--- a/elf/dl-audit.c
++++ b/elf/dl-audit.c
+@@ -108,6 +108,21 @@ _dl_audit_objclose (struct link_map *l)
+ }
+ }
+
++void
++_dl_audit_preinit (struct link_map *l)
++{
++ if (__glibc_likely (GLRO(dl_naudit) == 0))
++ return;
++
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ if (afct->preinit != NULL)
++ afct->preinit (&link_map_audit_state (l, cnt)->cookie);
++ afct = afct->next;
++ }
++}
++
+ void
+ _dl_audit_symbind_alt (struct link_map *l, const ElfW(Sym) *ref, void **value,
+ lookup_t result)
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index fa55c3bde10de52e..03676b474c3d37a3 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -1295,6 +1295,9 @@ void _dl_audit_objopen (struct link_map *l, Lmid_t nsid)
+ void _dl_audit_objclose (struct link_map *l)
+ attribute_hidden;
+
++/* Call the la_preinit from the audit modules for the link_map L. */
++void _dl_audit_preinit (struct link_map *l);
++
+ /* Call the la_symbind{32,64} from the audit modules for the link_map L. */
+ void _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result,
+ const ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value,
diff --git a/glibc-rh2047981-21.patch b/glibc-rh2047981-21.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ea5003f29abe39ff227b6831792412dc1f24ad5a
--- /dev/null
+++ b/glibc-rh2047981-21.patch
@@ -0,0 +1,205 @@
+commit eff687e8462b0eaf65992a6031b54a4b1cd16796
+Author: Adhemerval Zanella
+Date: Thu Jul 22 17:45:33 2021 -0300
+
+ elf: Add _dl_audit_pltenter
+
+ It consolidates the code required to call la_pltenter audit
+ callback.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+diff --git a/elf/dl-audit.c b/elf/dl-audit.c
+index 0b6fac8e48877c93..15250c67e8ac1658 100644
+--- a/elf/dl-audit.c
++++ b/elf/dl-audit.c
+@@ -17,7 +17,9 @@
+ . */
+
+ #include
++#include
+ #include
++#include
+
+ void
+ _dl_audit_activity_map (struct link_map *l, int action)
+@@ -243,3 +245,78 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result,
+ reloc_result->flags = flags;
+ *value = DL_FIXUP_ADDR_VALUE (sym.st_value);
+ }
++
++void
++_dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result,
++ DL_FIXUP_VALUE_TYPE *value, void *regs, long int *framesize)
++{
++ /* Don't do anything if no auditor wants to intercept this call. */
++ if (GLRO(dl_naudit) == 0
++ || (reloc_result->enterexit & LA_SYMB_NOPLTENTER))
++ return;
++
++ /* Sanity check: DL_FIXUP_VALUE_CODE_ADDR (value) should have been
++ initialized earlier in this function or in another thread. */
++ assert (DL_FIXUP_VALUE_CODE_ADDR (*value) != 0);
++ ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
++ l_info[DT_SYMTAB])
++ + reloc_result->boundndx);
++
++ /* Set up the sym parameter. */
++ ElfW(Sym) sym = *defsym;
++ sym.st_value = DL_FIXUP_VALUE_ADDR (*value);
++
++ /* Get the symbol name. */
++ const char *strtab = (const void *) D_PTR (reloc_result->bound,
++ l_info[DT_STRTAB]);
++ const char *symname = strtab + sym.st_name;
++
++ /* Keep track of overwritten addresses. */
++ unsigned int flags = reloc_result->flags;
++
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ if (afct->ARCH_LA_PLTENTER != NULL
++ && (reloc_result->enterexit
++ & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0)
++ {
++ long int new_framesize = -1;
++ struct auditstate *l_state = link_map_audit_state (l, cnt);
++ struct auditstate *bound_state
++ = link_map_audit_state (reloc_result->bound, cnt);
++ uintptr_t new_value
++ = afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx,
++ &l_state->cookie, &bound_state->cookie,
++ regs, &flags, symname, &new_framesize);
++ if (new_value != (uintptr_t) sym.st_value)
++ {
++ flags |= LA_SYMB_ALTVALUE;
++ sym.st_value = new_value;
++ }
++
++ /* Remember the results for every audit library and store a summary
++ in the first two bits. */
++ reloc_result->enterexit |= ((flags & (LA_SYMB_NOPLTENTER
++ | LA_SYMB_NOPLTEXIT))
++ << (2 * (cnt + 1)));
++
++ if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT
++ << (2 * (cnt + 1))))
++ == 0 && new_framesize != -1 && *framesize != -2)
++ {
++ /* If this is the first call providing information, use it. */
++ if (*framesize == -1)
++ *framesize = new_framesize;
++ /* If two pltenter calls provide conflicting information, use
++ the larger value. */
++ else if (new_framesize != *framesize)
++ *framesize = MAX (new_framesize, *framesize);
++ }
++ }
++
++ afct = afct->next;
++ }
++
++ *value = DL_FIXUP_ADDR_VALUE (sym.st_value);
++}
+diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
+index d4840a7c17441126..b46f7d7376e65361 100644
+--- a/elf/dl-runtime.c
++++ b/elf/dl-runtime.c
+@@ -319,78 +319,7 @@ _dl_profile_fixup (
+ #ifdef SHARED
+ /* Auditing checkpoint: report the PLT entering and allow the
+ auditors to change the value. */
+- if (GLRO(dl_naudit) > 0
+- /* Don't do anything if no auditor wants to intercept this call. */
+- && (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0)
+- {
+- /* Sanity check: DL_FIXUP_VALUE_CODE_ADDR (value) should have been
+- initialized earlier in this function or in another thread. */
+- assert (DL_FIXUP_VALUE_CODE_ADDR (value) != 0);
+- ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
+- l_info[DT_SYMTAB])
+- + reloc_result->boundndx);
+-
+- /* Set up the sym parameter. */
+- ElfW(Sym) sym = *defsym;
+- sym.st_value = DL_FIXUP_VALUE_ADDR (value);
+-
+- /* Get the symbol name. */
+- const char *strtab = (const void *) D_PTR (reloc_result->bound,
+- l_info[DT_STRTAB]);
+- const char *symname = strtab + sym.st_name;
+-
+- /* Keep track of overwritten addresses. */
+- unsigned int flags = reloc_result->flags;
+-
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->ARCH_LA_PLTENTER != NULL
+- && (reloc_result->enterexit
+- & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0)
+- {
+- long int new_framesize = -1;
+- struct auditstate *l_state = link_map_audit_state (l, cnt);
+- struct auditstate *bound_state
+- = link_map_audit_state (reloc_result->bound, cnt);
+- uintptr_t new_value
+- = afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx,
+- &l_state->cookie,
+- &bound_state->cookie,
+- regs, &flags, symname,
+- &new_framesize);
+- if (new_value != (uintptr_t) sym.st_value)
+- {
+- flags |= LA_SYMB_ALTVALUE;
+- sym.st_value = new_value;
+- }
+-
+- /* Remember the results for every audit library and
+- store a summary in the first two bits. */
+- reloc_result->enterexit
+- |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
+- << (2 * (cnt + 1)));
+-
+- if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT
+- << (2 * (cnt + 1))))
+- == 0 && new_framesize != -1 && framesize != -2)
+- {
+- /* If this is the first call providing information,
+- use it. */
+- if (framesize == -1)
+- framesize = new_framesize;
+- /* If two pltenter calls provide conflicting information,
+- use the larger value. */
+- else if (new_framesize != framesize)
+- framesize = MAX (new_framesize, framesize);
+- }
+- }
+-
+- afct = afct->next;
+- }
+-
+- value = DL_FIXUP_ADDR_VALUE (sym.st_value);
+- }
++ _dl_audit_pltenter (l, reloc_result, &value, regs, &framesize);
+ #endif
+
+ /* Store the frame size information. */
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 03676b474c3d37a3..47a9dee5b1c0ca63 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -1307,6 +1307,10 @@ void _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result,
+ void _dl_audit_symbind_alt (struct link_map *l, const ElfW(Sym) *ref,
+ void **value, lookup_t result);
+ rtld_hidden_proto (_dl_audit_symbind_alt)
++void _dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result,
++ DL_FIXUP_VALUE_TYPE *value, void *regs,
++ long int *framesize)
++ attribute_hidden;
+ #endif /* SHARED */
+
+ __END_DECLS
diff --git a/glibc-rh2047981-22.patch b/glibc-rh2047981-22.patch
new file mode 100644
index 0000000000000000000000000000000000000000..17c35d5c96293e5d1e6166177e5fe522f9fe745d
--- /dev/null
+++ b/glibc-rh2047981-22.patch
@@ -0,0 +1,795 @@
+commit 8c0664e2b861fd3789602cc0b0b1922b0e20cb3a
+Author: Adhemerval Zanella
+Date: Thu Jul 22 18:02:42 2021 -0300
+
+ elf: Add _dl_audit_pltexit
+
+ It consolidates the code required to call la_pltexit audit
+ callback.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+Conflicts:
+ nptl/tst-atfork4mod.c
+ sysdeps/powerpc/fpu/s_fmaf.S
+ sysdeps/powerpc/powerpc32/power4/multiarch/wcscpy-ppc32.c
+ sysdeps/powerpc/powerpc64/power5+/fpu/s_floor.S
+ Without d6d89608ac8cf2b37c75debad1fff653f6939f90 we
+ don't have dl-machine-rel.h so git picks a match for
+ all four files above, instead we modify dl-machine.h
+ for the targets:
+ sysdeps/i386/dl-machine.h
+ sysdeps/arm/dl-machine.h
+ sysdeps/mips/dl-machine.h
+ The fourth is the generic file and without it we
+ add the PLTREL macro to each target:
+ sysdeps/aarch64/dl-machine.h
+ sysdeps/powerpc/powerpc32/dl-machine.h
+ sysdeps/powerpc/powerpc64/dl-machine.h
+ sysdeps/s390/s390-32/dl-machine.h
+ sysdeps/s390/s390-64/dl-machine.h
+ sysdeps/x86_64/dl-machine.h
+ sysdeps/s390/s390-32/dl-trampoline.h
+ sysdeps/s390/s390-64/dl-trampoline.h
+
+diff --git a/elf/dl-audit.c b/elf/dl-audit.c
+index 15250c67e8ac1658..152712b12fed6de2 100644
+--- a/elf/dl-audit.c
++++ b/elf/dl-audit.c
+@@ -20,6 +20,8 @@
+ #include
+ #include
+ #include
++#include
++#include
+
+ void
+ _dl_audit_activity_map (struct link_map *l, int action)
+@@ -320,3 +322,48 @@ _dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result,
+
+ *value = DL_FIXUP_ADDR_VALUE (sym.st_value);
+ }
++
++void
++DL_ARCH_FIXUP_ATTRIBUTE
++_dl_audit_pltexit (struct link_map *l, ElfW(Word) reloc_arg,
++ const void *inregs, void *outregs)
++{
++ const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]);
++
++ /* This is the address in the array where we store the result of previous
++ relocations. */
++ // XXX Maybe the bound information must be stored on the stack since
++ // XXX with bind_not a new value could have been stored in the meantime.
++ struct reloc_result *reloc_result =
++ &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))];
++ ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
++ l_info[DT_SYMTAB])
++ + reloc_result->boundndx);
++
++ /* Set up the sym parameter. */
++ ElfW(Sym) sym = *defsym;
++ sym.st_value = DL_FIXUP_VALUE_ADDR (reloc_result->addr);
++
++ /* Get the symbol name. */
++ const char *strtab = (const void *) D_PTR (reloc_result->bound,
++ l_info[DT_STRTAB]);
++ const char *symname = strtab + sym.st_name;
++
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ if (afct->ARCH_LA_PLTEXIT != NULL
++ && (reloc_result->enterexit
++ & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0)
++ {
++ struct auditstate *l_state = link_map_audit_state (l, cnt);
++ struct auditstate *bound_state
++ = link_map_audit_state (reloc_result->bound, cnt);
++ afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx,
++ &l_state->cookie, &bound_state->cookie,
++ inregs, outregs, symname);
++ }
++
++ afct = afct->next;
++ }
++}
+diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
+index b46f7d7376e65361..ec0b2164825fa538 100644
+--- a/elf/dl-runtime.c
++++ b/elf/dl-runtime.c
+@@ -16,8 +16,6 @@
+ License along with the GNU C Library; if not, see
+ . */
+
+-#define IN_DL_RUNTIME 1 /* This can be tested in dl-machine.h. */
+-
+ #include
+ #include
+ #include
+@@ -30,19 +28,6 @@
+ #include
+
+
+-#if (!ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
+- || ELF_MACHINE_NO_REL
+-# define PLTREL ElfW(Rela)
+-#else
+-# define PLTREL ElfW(Rel)
+-#endif
+-
+-/* The fixup functions might have need special attributes. If none
+- are provided define the macro as empty. */
+-#ifndef ARCH_FIXUP_ATTRIBUTE
+-# define ARCH_FIXUP_ATTRIBUTE
+-#endif
+-
+ /* This function is called through a special trampoline from the PLT the
+ first time each PLT entry is called. We must perform the relocation
+ specified in the PLT of the given shared object, and return the resolved
+@@ -51,7 +36,7 @@
+ function. */
+
+ DL_FIXUP_VALUE_TYPE
+-attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
++attribute_hidden __attribute ((noinline)) DL_ARCH_FIXUP_ATTRIBUTE
+ _dl_fixup (
+ # ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
+ ELF_MACHINE_RUNTIME_FIXUP_ARGS,
+@@ -147,7 +132,8 @@ _dl_fixup (
+
+ #ifndef PROF
+ DL_FIXUP_VALUE_TYPE
+-__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
++__attribute ((noinline))
++DL_ARCH_FIXUP_ATTRIBUTE
+ _dl_profile_fixup (
+ #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
+ ELF_MACHINE_RUNTIME_FIXUP_ARGS,
+@@ -331,52 +317,3 @@ _dl_profile_fixup (
+ }
+
+ #endif /* PROF */
+-
+-
+-#include
+-void
+-ARCH_FIXUP_ATTRIBUTE
+-_dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_arg,
+- const void *inregs, void *outregs)
+-{
+-#ifdef SHARED
+- const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]);
+-
+- /* This is the address in the array where we store the result of previous
+- relocations. */
+- // XXX Maybe the bound information must be stored on the stack since
+- // XXX with bind_not a new value could have been stored in the meantime.
+- struct reloc_result *reloc_result =
+- &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))];
+- ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
+- l_info[DT_SYMTAB])
+- + reloc_result->boundndx);
+-
+- /* Set up the sym parameter. */
+- ElfW(Sym) sym = *defsym;
+- sym.st_value = DL_FIXUP_VALUE_ADDR (reloc_result->addr);
+-
+- /* Get the symbol name. */
+- const char *strtab = (const void *) D_PTR (reloc_result->bound,
+- l_info[DT_STRTAB]);
+- const char *symname = strtab + sym.st_name;
+-
+- struct audit_ifaces *afct = GLRO(dl_audit);
+- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+- {
+- if (afct->ARCH_LA_PLTEXIT != NULL
+- && (reloc_result->enterexit
+- & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0)
+- {
+- struct auditstate *l_state = link_map_audit_state (l, cnt);
+- struct auditstate *bound_state
+- = link_map_audit_state (reloc_result->bound, cnt);
+- afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx,
+- &l_state->cookie, &bound_state->cookie,
+- inregs, outregs, symname);
+- }
+-
+- afct = afct->next;
+- }
+-#endif
+-}
+diff --git a/elf/dl-support.c b/elf/dl-support.c
+index 3e5531138eaa18f8..e9943e889ef447ad 100644
+--- a/elf/dl-support.c
++++ b/elf/dl-support.c
+@@ -399,3 +399,11 @@ _dl_get_dl_main_map (void)
+ return &_dl_main_map;
+ }
+ #endif
++
++/* This is used by _dl_runtime_profile, not used on static code. */
++void
++DL_ARCH_FIXUP_ATTRIBUTE
++_dl_audit_pltexit (struct link_map *l, ElfW(Word) reloc_arg,
++ const void *inregs, void *outregs)
++{
++}
+diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
+index 5eab544afe2717f7..c13d896a57811c7d 100644
+--- a/sysdeps/aarch64/dl-machine.h
++++ b/sysdeps/aarch64/dl-machine.h
+@@ -196,6 +196,7 @@ _dl_start_user: \n\
+ /* AArch64 uses RELA not REL */
+ #define ELF_MACHINE_NO_REL 1
+ #define ELF_MACHINE_NO_RELA 0
++#define PLTREL ElfW(Rela)
+
+ #define DL_PLATFORM_INIT dl_platform_init ()
+
+diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S
+index a86d0722d4a0415b..18740398e63fdf97 100644
+--- a/sysdeps/aarch64/dl-trampoline.S
++++ b/sysdeps/aarch64/dl-trampoline.S
+@@ -277,7 +277,7 @@ _dl_runtime_profile:
+ ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0]
+ add x2, x29, #OFFSET_RG
+ add x3, x29, #OFFSET_RV
+- bl _dl_call_pltexit
++ bl _dl_audit_pltexit
+
+ ldp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0]
+ ldp d0, d1, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*0]
+diff --git a/sysdeps/alpha/dl-trampoline.S b/sysdeps/alpha/dl-trampoline.S
+index b326b37acedb5eaa..3acf5dec8d9585da 100644
+--- a/sysdeps/alpha/dl-trampoline.S
++++ b/sysdeps/alpha/dl-trampoline.S
+@@ -187,7 +187,7 @@ _dl_runtime_profile_new:
+ jsr $26, ($27), 0
+ ldgp $29, 0($26)
+
+- /* Set up for call to _dl_call_pltexit. */
++ /* Set up for call to _dl_audit_pltexit. */
+ ldq $16, 16*8($15)
+ ldq $17, 17*8($15)
+ stq $0, 16*8($15)
+@@ -196,7 +196,7 @@ _dl_runtime_profile_new:
+ lda $19, 16*8($15)
+ stt $f0, 18*8($15)
+ stt $f1, 19*8($15)
+- bsr $26, _dl_call_pltexit !samegp
++ bsr $26, _dl_audit_pltexit !samegp
+
+ mov $15, $30
+ cfi_def_cfa_register (30)
+@@ -518,7 +518,7 @@ _dl_runtime_profile_old:
+ jsr $26, ($27), 0
+ ldgp $29, 0($26)
+
+- /* Set up for call to _dl_call_pltexit. */
++ /* Set up for call to _dl_audit_pltexit. */
+ ldq $16, 48*8($15)
+ ldq $17, 49*8($15)
+ stq $0, 46*8($15)
+@@ -527,7 +527,7 @@ _dl_runtime_profile_old:
+ lda $19, 46*8($15)
+ stt $f0, 48*8($15)
+ stt $f1, 49*8($15)
+- bsr $26, _dl_call_pltexit !samegp
++ bsr $26, _dl_audit_pltexit !samegp
+
+ mov $15, $30
+ cfi_def_cfa_register (30)
+diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h
+index 1a4fd3f17b6df7da..9b5d0567df984c5d 100644
+--- a/sysdeps/arm/dl-machine.h
++++ b/sysdeps/arm/dl-machine.h
+@@ -260,6 +260,8 @@ _dl_start_user:\n\
+ Prelinked libraries may use Elf32_Rela though. */
+ #define ELF_MACHINE_PLT_REL 1
+
++#define PLTREL ElfW(Rel)
++
+ /* We define an initialization functions. This is called very early in
+ _dl_sysdep_start. */
+ #define DL_PLATFORM_INIT dl_platform_init ()
+diff --git a/sysdeps/arm/dl-trampoline.S b/sysdeps/arm/dl-trampoline.S
+index c731b012869a9cbc..ced1b1cb1017d677 100644
+--- a/sysdeps/arm/dl-trampoline.S
++++ b/sysdeps/arm/dl-trampoline.S
+@@ -194,7 +194,7 @@ _dl_runtime_profile:
+ ldmia ip, {r0,r1}
+ add r2, r7, #72
+ add r3, r7, #0
+- bl _dl_call_pltexit
++ bl _dl_audit_pltexit
+
+ @ Return to caller.
+ ldmia r7, {r0-r3}
+diff --git a/sysdeps/generic/dl-fixup-attribute.h b/sysdeps/generic/dl-fixup-attribute.h
+new file mode 100644
+index 0000000000000000..aa92169b709b3fea
+--- /dev/null
++++ b/sysdeps/generic/dl-fixup-attribute.h
+@@ -0,0 +1,24 @@
++/* ABI specifics for lazy resolution functions.
++ Copyright (C) 2021 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
++ . */
++
++#ifndef _DL_FIXUP_ATTRIBUTE_H
++#define _DL_FIXUP_ATTRIBUTE_H
++
++#define DL_ARCH_FIXUP_ATTRIBUTE
++
++#endif
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 47a9dee5b1c0ca63..29b77b35175c1116 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -35,6 +35,7 @@
+ #include
+ #include
+ #include
++#include
+ #include
+ #include
+ #include
+@@ -1311,6 +1312,11 @@ void _dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result,
+ DL_FIXUP_VALUE_TYPE *value, void *regs,
+ long int *framesize)
+ attribute_hidden;
++void DL_ARCH_FIXUP_ATTRIBUTE _dl_audit_pltexit (struct link_map *l,
++ ElfW(Word) reloc_arg,
++ const void *inregs,
++ void *outregs)
++ attribute_hidden;
+ #endif /* SHARED */
+
+ __END_DECLS
+diff --git a/sysdeps/hppa/dl-runtime.c b/sysdeps/hppa/dl-runtime.c
+index 2d061b150f0602c1..4c323131f937094b 100644
+--- a/sysdeps/hppa/dl-runtime.c
++++ b/sysdeps/hppa/dl-runtime.c
+@@ -26,7 +26,7 @@
+ _dl_fixup with the relocation offset. */
+
+ ElfW(Word)
+-attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
++attribute_hidden __attribute ((noinline)) DL_ARCH_FIXUP_ATTRIBUTE
+ _dl_fix_reloc_arg (struct fdesc *fptr, struct link_map *l)
+ {
+ Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type;
+diff --git a/sysdeps/hppa/dl-trampoline.S b/sysdeps/hppa/dl-trampoline.S
+index 7ee4331cc2e7deff..3c83c8542f4fc63f 100644
+--- a/sysdeps/hppa/dl-trampoline.S
++++ b/sysdeps/hppa/dl-trampoline.S
+@@ -275,7 +275,7 @@ L(cont):
+ ldw -4(%sp),%r1
+ copy %r1, %sp
+
+- /* Arguments to _dl_call_pltexit */
++ /* Arguments to _dl_audit_pltexit */
+ ldw -116(%sp), %r26 /* (1) got[1] == struct link_map */
+ ldw -120(%sp), %r25 /* (2) reloc offsets */
+ ldo -56(%sp), %r24 /* (3) *La_hppa_regs */
+@@ -287,8 +287,8 @@ L(cont):
+ ldo -128(%sp), %r1
+ fstd %fr4,0(%r1)
+
+- /* Call _dl_call_pltexit */
+- bl _dl_call_pltexit,%rp
++ /* Call _dl_audit_pltexit */
++ bl _dl_audit_pltexit,%rp
+ nop
+
+ /* Restore *La_hppa_retval */
+diff --git a/sysdeps/i386/dl-fixup-attribute.h b/sysdeps/i386/dl-fixup-attribute.h
+new file mode 100644
+index 0000000000000000..c10e9936f4db7254
+--- /dev/null
++++ b/sysdeps/i386/dl-fixup-attribute.h
+@@ -0,0 +1,30 @@
++/* ABI specifics for lazy resolution functions. i386 version.
++ Copyright (C) 2021 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
++ . */
++
++#ifndef _DL_FIXUP_ATTRIBUTE_H
++#define _DL_FIXUP_ATTRIBUTE_H
++
++/* We cannot use this scheme for profiling because the _mcount call destroys
++ the passed register information. */
++#ifndef PROF
++# define DL_ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), stdcall, unused))
++#else
++# define DL_ARCH_FIXUP_ATTRIBUTE
++#endif
++
++#endif
+diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
+index 5ba95b9e4af49942..30c3464fc4ac19d8 100644
+--- a/sysdeps/i386/dl-machine.h
++++ b/sysdeps/i386/dl-machine.h
+@@ -119,29 +119,6 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
+ return lazy;
+ }
+
+-#ifdef IN_DL_RUNTIME
+-
+-# ifndef PROF
+-/* We add a declaration of this function here so that in dl-runtime.c
+- the ELF_MACHINE_RUNTIME_TRAMPOLINE macro really can pass the parameters
+- in registers.
+-
+- We cannot use this scheme for profiling because the _mcount call
+- destroys the passed register information. */
+-#define ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), stdcall, unused))
+-
+-extern ElfW(Addr) _dl_fixup (struct link_map *l,
+- ElfW(Word) reloc_offset)
+- ARCH_FIXUP_ATTRIBUTE;
+-extern ElfW(Addr) _dl_profile_fixup (struct link_map *l,
+- ElfW(Word) reloc_offset,
+- ElfW(Addr) retaddr, void *regs,
+- long int *framesizep)
+- ARCH_FIXUP_ATTRIBUTE;
+-# endif
+-
+-#endif
+-
+ /* Mask identifying addresses reserved for the user program,
+ where the dynamic linker should not map anything. */
+ #define ELF_MACHINE_USER_ADDRESS_MASK 0xf8000000UL
+@@ -240,6 +217,8 @@ _dl_start_user:\n\
+ Prelinked libraries may use Elf32_Rela though. */
+ #define ELF_MACHINE_PLT_REL 1
+
++#define PLTREL ElfW(Rel)
++
+ /* We define an initialization functions. This is called very early in
+ _dl_sysdep_start. */
+ #define DL_PLATFORM_INIT dl_platform_init ()
+diff --git a/sysdeps/i386/dl-trampoline.S b/sysdeps/i386/dl-trampoline.S
+index 6dc03192168ae2f3..a738b291a79bf8c2 100644
+--- a/sysdeps/i386/dl-trampoline.S
++++ b/sysdeps/i386/dl-trampoline.S
+@@ -265,7 +265,7 @@ _dl_runtime_profile:
+ movl (LRV_SIZE + 4 + LR_SIZE)(%esp), %eax
+ # PLT1
+ movl (LRV_SIZE + 4 + LR_SIZE + 4)(%esp), %edx
+- call _dl_call_pltexit
++ call _dl_audit_pltexit
+ movl LRV_EAX_OFFSET(%esp), %eax
+ movl LRV_EDX_OFFSET(%esp), %edx
+ fldt LRV_ST1_OFFSET(%esp)
+diff --git a/sysdeps/ia64/dl-trampoline.S b/sysdeps/ia64/dl-trampoline.S
+index fc24c425bfe6907b..caeca3afcd7db6b6 100644
+--- a/sysdeps/ia64/dl-trampoline.S
++++ b/sysdeps/ia64/dl-trampoline.S
+@@ -133,7 +133,7 @@ END(_dl_runtime_resolve)
+
+
+ /* The fourth argument to _dl_profile_fixup and the third one to
+- _dl_call_pltexit are a pointer to La_ia64_regs:
++ _dl_audit_pltexit are a pointer to La_ia64_regs:
+
+ 8byte r8
+ 8byte r9
+@@ -159,7 +159,7 @@ END(_dl_runtime_resolve)
+ 8byte sp
+
+ The fifth argument to _dl_profile_fixup is a pointer to long int.
+- The fourth argument to _dl_call_pltexit is a pointer to
++ The fourth argument to _dl_audit_pltexit is a pointer to
+ La_ia64_retval:
+
+ 8byte r8
+@@ -261,7 +261,7 @@ ENTRY(_dl_runtime_profile)
+ }
+ { .mii
+ mov r18 = ar.unat /* save it in La_ia64_regs */
+- mov loc7 = out3 /* save it for _dl_call_pltexit */
++ mov loc7 = out3 /* save it for _dl_audit_pltexit */
+ mov loc5 = r11 /* preserve language specific register */
+ }
+ { .mmi
+@@ -272,7 +272,7 @@ ENTRY(_dl_runtime_profile)
+ }
+ { .mii
+ mov ar.unat = r17 /* restore it for function call */
+- mov loc8 = r16 /* save it for _dl_call_pltexit */
++ mov loc8 = r16 /* save it for _dl_audit_pltexit */
+ nop.i 0x0
+ }
+ { .mmi
+@@ -291,7 +291,7 @@ ENTRY(_dl_runtime_profile)
+ { .mmi
+ stf.spill [r2] = f14, 32
+ stf.spill [r3] = f15, 24
+- mov loc9 = out1 /* save it for _dl_call_pltexit */
++ mov loc9 = out1 /* save it for _dl_audit_pltexit */
+ ;;
+ }
+ { .mmb
+@@ -426,7 +426,7 @@ ENTRY(_dl_runtime_profile)
+ br.call.sptk.many b0 = b6
+ }
+ { .mii
+- /* Prepare stack for _dl_call_pltexit. Loc10 has the original
++ /* Prepare stack for _dl_audit_pltexit. Loc10 has the original
+ stack pointer. */
+ adds r12 = -PLTEXIT_FRAME_SIZE, loc10
+ adds r2 = -(PLTEXIT_FRAME_SIZE - 16), loc10
+@@ -461,14 +461,14 @@ ENTRY(_dl_runtime_profile)
+ { .mmi
+ stf.spill [r2] = f12, 32
+ stf.spill [r3] = f13, 32
+- /* We need to restore gp for _dl_call_pltexit. */
++ /* We need to restore gp for _dl_audit_pltexit. */
+ mov gp = loc11
+ ;;
+ }
+ { .mmb
+ stf.spill [r2] = f14
+ stf.spill [r3] = f15
+- br.call.sptk.many b0 = _dl_call_pltexit
++ br.call.sptk.many b0 = _dl_audit_pltexit
+ }
+ { .mmi
+ /* Load all the non-floating and floating return values. Skip
+diff --git a/sysdeps/m68k/dl-trampoline.S b/sysdeps/m68k/dl-trampoline.S
+index 7e1eace26b4a519d..27282ca8a6b1dada 100644
+--- a/sysdeps/m68k/dl-trampoline.S
++++ b/sysdeps/m68k/dl-trampoline.S
+@@ -202,7 +202,7 @@ _dl_runtime_profile:
+ cfi_adjust_cfa_offset (4)
+ move.l (32+FPSPACE)(%sp), -(%sp)
+ cfi_adjust_cfa_offset (4)
+- jbsr _dl_call_pltexit
++ jbsr _dl_audit_pltexit
+ lea 16(%sp), %sp
+ cfi_adjust_cfa_offset (-16)
+ move.l (%sp)+, %d0
+diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h
+index b41e10647d81843b..d4bd8b62f4b036a3 100644
+--- a/sysdeps/mips/dl-machine.h
++++ b/sysdeps/mips/dl-machine.h
+@@ -63,6 +63,7 @@
+ #define ELF_MACHINE_PLT_REL 1
+ #define ELF_MACHINE_NO_REL 0
+ #define ELF_MACHINE_NO_RELA 0
++#define PLTREL ElfW(Rel)
+
+ /* Translate a processor specific dynamic tag to the index
+ in l_info array. */
+diff --git a/sysdeps/powerpc/powerpc32/dl-machine.h b/sysdeps/powerpc/powerpc32/dl-machine.h
+index 31c7f3f95a2ce1b2..84322595793dc8bb 100644
+--- a/sysdeps/powerpc/powerpc32/dl-machine.h
++++ b/sysdeps/powerpc/powerpc32/dl-machine.h
+@@ -150,6 +150,7 @@ __elf_preferred_address(struct link_map *loader, size_t maplength,
+ /* The PowerPC never uses REL relocations. */
+ #define ELF_MACHINE_NO_REL 1
+ #define ELF_MACHINE_NO_RELA 0
++#define PLTREL ElfW(Rela)
+
+ /* We define an initialization function to initialize HWCAP/HWCAP2 and
+ platform data so it can be copied into the TCB later. This is called
+diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h
+index 35996bb9173da231..3af1f708378f9a3c 100644
+--- a/sysdeps/powerpc/powerpc64/dl-machine.h
++++ b/sysdeps/powerpc/powerpc64/dl-machine.h
+@@ -297,6 +297,7 @@ BODY_PREFIX "_dl_start_user:\n" \
+ /* The PowerPC never uses REL relocations. */
+ #define ELF_MACHINE_NO_REL 1
+ #define ELF_MACHINE_NO_RELA 0
++#define PLTREL ElfW(Rela)
+
+ /* We define an initialization function to initialize HWCAP/HWCAP2 and
+ platform data so it can be copied into the TCB later. This is called
+diff --git a/sysdeps/powerpc/powerpc64/dl-trampoline.S b/sysdeps/powerpc/powerpc64/dl-trampoline.S
+index aa141dc44b980d9b..23290d32360507fd 100644
+--- a/sysdeps/powerpc/powerpc64/dl-trampoline.S
++++ b/sysdeps/powerpc/powerpc64/dl-trampoline.S
+@@ -197,7 +197,7 @@ END(_dl_runtime_resolve)
+ #ifndef PROF
+ ENTRY (_dl_profile_resolve, 4)
+ /* Spill r30, r31 to preserve the link_map* and reloc_addr, in case we
+- need to call _dl_call_pltexit. */
++ need to call _dl_audit_pltexit. */
+ std r31,-8(r1)
+ std r30,-16(r1)
+ /* We need to save the registers used to pass parameters, ie. r3 thru
+@@ -452,7 +452,7 @@ L(restoreFXR2):
+ L(callpltexit):
+ addi r5,r1,INT_PARMS
+ addi r6,r1,INT_RTN
+- bl JUMPTARGET(_dl_call_pltexit)
++ bl JUMPTARGET(_dl_audit_pltexit)
+ #ifndef SHARED
+ nop
+ #endif
+diff --git a/sysdeps/s390/s390-32/dl-machine.h b/sysdeps/s390/s390-32/dl-machine.h
+index ded41adff80346b6..2f3bb085ae2b6794 100644
+--- a/sysdeps/s390/s390-32/dl-machine.h
++++ b/sysdeps/s390/s390-32/dl-machine.h
+@@ -279,6 +279,7 @@ _dl_start_user:\n\
+ /* The S390 never uses Elf32_Rel relocations. */
+ #define ELF_MACHINE_NO_REL 1
+ #define ELF_MACHINE_NO_RELA 0
++#define PLTREL ElfW(Rela)
+
+ /* We define an initialization functions. This is called very early in
+ _dl_sysdep_start. */
+diff --git a/sysdeps/s390/s390-32/dl-trampoline.h b/sysdeps/s390/s390-32/dl-trampoline.h
+index d36c002743bf2f0c..c447a41f067c462b 100644
+--- a/sysdeps/s390/s390-32/dl-trampoline.h
++++ b/sysdeps/s390/s390-32/dl-trampoline.h
+@@ -207,7 +207,7 @@ _dl_runtime_profile:
+ basr %r1,0
+ 5: l %r14,7f-5b(%r1)
+ la %r5,40(%r12) # pointer to struct La_s390_32_retval
+- bas %r14,0(%r14,%r1) # call _dl_call_pltexit
++ bas %r14,0(%r14,%r1) # call _dl_audit_pltexit
+
+ lr %r15,%r12 # remove stack frame
+ cfi_def_cfa_register (15)
+@@ -224,7 +224,7 @@ _dl_runtime_profile:
+ br %r14
+
+ 6: .long _dl_profile_fixup - 0b
+-7: .long _dl_call_pltexit - 5b
++7: .long _dl_audit_pltexit - 5b
+ cfi_endproc
+ .size _dl_runtime_profile, .-_dl_runtime_profile
+ #endif
+diff --git a/sysdeps/s390/s390-64/dl-machine.h b/sysdeps/s390/s390-64/dl-machine.h
+index 36327c40a1972dd7..033e7c9916e751f4 100644
+--- a/sysdeps/s390/s390-64/dl-machine.h
++++ b/sysdeps/s390/s390-64/dl-machine.h
+@@ -228,6 +228,7 @@ _dl_start_user:\n\
+ /* The 64 bit S/390 never uses Elf64_Rel relocations. */
+ #define ELF_MACHINE_NO_REL 1
+ #define ELF_MACHINE_NO_RELA 0
++#define PLTREL ElfW(Rela)
+
+ /* We define an initialization functions. This is called very early in
+ _dl_sysdep_start. */
+diff --git a/sysdeps/s390/s390-64/dl-trampoline.h b/sysdeps/s390/s390-64/dl-trampoline.h
+index d313fd521db0b859..18534d629ebc00e2 100644
+--- a/sysdeps/s390/s390-64/dl-trampoline.h
++++ b/sysdeps/s390/s390-64/dl-trampoline.h
+@@ -203,7 +203,7 @@ _dl_runtime_profile:
+ lmg %r2,%r4,48(%r12) # r2, r3: load arguments saved by PLT
+ # r4: pointer to struct La_s390_64_regs
+ la %r5,72(%r12) # pointer to struct La_s390_64_retval
+- brasl %r14,_dl_call_pltexit
++ brasl %r14,_dl_audit_pltexit
+
+ lgr %r15,%r12 # remove stack frame
+ cfi_def_cfa_register (15)
+diff --git a/sysdeps/sh/dl-trampoline.S b/sysdeps/sh/dl-trampoline.S
+index 0c8f84d26d3015ca..73f865f2af4e2d48 100644
+--- a/sysdeps/sh/dl-trampoline.S
++++ b/sysdeps/sh/dl-trampoline.S
+@@ -423,8 +423,8 @@ _dl_runtime_profile:
+ .align 2
+ #ifdef SHARED
+ 7: .long _GLOBAL_OFFSET_TABLE_
+-8: .long _dl_call_pltexit@GOTOFF
++8: .long _dl_audit_pltexit@GOTOFF
+ #else
+-8: .long _dl_call_pltexit
++8: .long _dl_audit_pltexit
+ #endif
+ .size _dl_runtime_profile, .-_dl_runtime_profile
+diff --git a/sysdeps/sparc/sparc32/dl-trampoline.S b/sysdeps/sparc/sparc32/dl-trampoline.S
+index 098ffcfacc55d0b6..18ef2f0d3655b3de 100644
+--- a/sysdeps/sparc/sparc32/dl-trampoline.S
++++ b/sysdeps/sparc/sparc32/dl-trampoline.S
+@@ -127,7 +127,7 @@ _dl_profile_invoke:
+ mov %l5, %o0
+ mov %l6, %o1
+ add %sp, (11 * 8), %o2
+- call _dl_call_pltexit
++ call _dl_audit_pltexit
+ add %sp, ( 9 * 8), %o3
+
+ ldd [%sp + ( 9 * 8)], %i0
+diff --git a/sysdeps/sparc/sparc64/dl-trampoline.S b/sysdeps/sparc/sparc64/dl-trampoline.S
+index 4948b88b9640691d..9c18ceb131c9a25b 100644
+--- a/sysdeps/sparc/sparc64/dl-trampoline.S
++++ b/sysdeps/sparc/sparc64/dl-trampoline.S
+@@ -196,7 +196,7 @@ _dl_profile_invoke:
+ mov %l5, %o0
+ mov %l6, %o1
+ add %sp, STACK_BIAS + (24 * 8), %o2
+- call _dl_call_pltexit
++ call _dl_audit_pltexit
+ add %sp, STACK_BIAS + (16 * 8), %o3
+
+ ldx [%sp + STACK_BIAS + (16 * 8)], %i0
+diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
+index 5262aa69c06aa8db..d30317980882ac51 100644
+--- a/sysdeps/x86_64/dl-machine.h
++++ b/sysdeps/x86_64/dl-machine.h
+@@ -210,6 +210,7 @@ _dl_start_user:\n\
+ /* The x86-64 never uses Elf64_Rel/Elf32_Rel relocations. */
+ #define ELF_MACHINE_NO_REL 1
+ #define ELF_MACHINE_NO_RELA 0
++#define PLTREL ElfW(Rela)
+
+ /* We define an initialization function. This is called very early in
+ _dl_sysdep_start. */
+diff --git a/sysdeps/x86_64/dl-runtime.h b/sysdeps/x86_64/dl-runtime.h
+index 3fa61d7a4697cf3f..379f8bd4dea8ef97 100644
+--- a/sysdeps/x86_64/dl-runtime.h
++++ b/sysdeps/x86_64/dl-runtime.h
+@@ -18,7 +18,7 @@
+ 02111-1307 USA. */
+
+ /* The ABI calls for the PLT stubs to pass the index of the relocation
+- and not its offset. In _dl_profile_fixup and _dl_call_pltexit we
++ and not its offset. In _dl_profile_fixup and _dl_audit_pltexit we
+ also use the index. Therefore it is wasteful to compute the offset
+ in the trampoline just to reverse the operation immediately
+ afterwards. */
+diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h
+index a28b1e73a4b187ba..256dfbb64df9f03d 100644
+--- a/sysdeps/x86_64/dl-trampoline.h
++++ b/sysdeps/x86_64/dl-trampoline.h
+@@ -388,7 +388,7 @@ _dl_runtime_profile:
+ jns 3f
+
+ /* There's nothing in the frame size, so there
+- will be no call to the _dl_call_pltexit. */
++ will be no call to the _dl_audit_pltexit. */
+
+ /* Get back registers content. */
+ movq LR_RCX_OFFSET(%rsp), %rcx
+@@ -436,7 +436,7 @@ _dl_runtime_profile:
+ mov 24(%rbx), %RSP_LP # Drop the copied stack content
+
+ /* Now we have to prepare the La_x86_64_retval structure for the
+- _dl_call_pltexit. The La_x86_64_regs is being pointed by rsp now,
++ _dl_audit_pltexit. The La_x86_64_regs is being pointed by rsp now,
+ so we just need to allocate the sizeof(La_x86_64_retval) space on
+ the stack, since the alignment has already been taken care of. */
+ # ifdef RESTORE_AVX
+@@ -491,7 +491,7 @@ _dl_runtime_profile:
+ movq 24(%rbx), %rdx # La_x86_64_regs argument to %rdx.
+ movq 40(%rbx), %rsi # Copy args pushed by PLT in register.
+ movq 32(%rbx), %rdi # %rdi: link_map, %rsi: reloc_index
+- call _dl_call_pltexit
++ call _dl_audit_pltexit
+
+ /* Restore return registers. */
+ movq LRV_RAX_OFFSET(%rsp), %rax
diff --git a/glibc-rh2047981-23.patch b/glibc-rh2047981-23.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b2e83f86f7f781aa87d53985ce5e954a59b4099f
--- /dev/null
+++ b/glibc-rh2047981-23.patch
@@ -0,0 +1,449 @@
+Added $(objpfx)tst-audit19a: $(libdl) to elf/Makefile since
+we still need $(libdl) in RHEL8.
+
+commit 063f9ba220f434c7f30dd65c4cff17c0c458a7cf
+Author: Adhemerval Zanella
+Date: Wed Jun 30 10:24:09 2021 -0300
+
+ elf: Avoid unnecessary slowdown from profiling with audit (BZ#15533)
+
+ The rtld-audit interfaces introduces a slowdown due to enabling
+ profiling instrumentation (as if LD_AUDIT implied LD_PROFILE).
+ However, instrumenting is only necessary if one of audit libraries
+ provides PLT callbacks (la_pltenter or la_pltexit symbols). Otherwise,
+ the slowdown can be avoided.
+
+ The following patch adjusts the logic that enables profiling to iterate
+ over all audit modules and check if any of those provides a PLT hook.
+ To keep la_symbind to work even without PLT callbacks, _dl_fixup now
+ calls the audit callback if the modules implements it.
+
+ Co-authored-by: Alexander Monakov
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+Conflicts:
+ elf/Makefile
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 08a32a712a34f2cc..0cc03ffe2984ee50 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -221,12 +221,14 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ tst-dlmopen-gethostbyname \
+ tst-audit17 \
+ tst-audit18 \
++ tst-audit19b \
+ # reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+ neededtest neededtest2 neededtest3 neededtest4 \
+ tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
+ tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \
+- tst-create_format1 tst-tls-surplus tst-dl-hwcaps_split
++ tst-create_format1 tst-tls-surplus tst-dl-hwcaps_split \
++ tst-audit19a
+ tests-container += tst-pldd tst-preload-pthread-libc
+ ifeq ($(build-hardcoded-path-in-tests),yes)
+ tests += tst-dlopen-aout
+@@ -358,6 +360,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ tst-dlmopen-gethostbyname-mod \
+ tst-auditmod18 \
+ tst-audit18mod \
++ tst-auditmod19a \
++ tst-auditmod19b \
++ tst-audit19bmod \
+
+ # Most modules build with _ISOMAC defined, but those filtered out
+ # depend on internal headers.
+@@ -1548,6 +1553,14 @@ $(objpfx)tst-audit18.out: $(objpfx)tst-auditmod18.so \
+ $(objpfx)tst-audit18mod.so
+ tst-audit18-ARGS = -- $(host-test-program-cmd)
+
++$(objpfx)tst-audit19a: $(libdl)
++$(objpfx)tst-audit19a.out: $(objpfx)tst-auditmod19a.so
++tst-audit19a-ENV = LD_AUDIT=$(objpfx)tst-auditmod19a.so
++
++$(objpfx)tst-audit19b.out: $(objpfx)tst-auditmod19b.so
++$(objpfx)tst-audit19b: $(objpfx)tst-audit19bmod.so
++tst-audit19b-ARGS = -- $(host-test-program-cmd)
++
+ # tst-sonamemove links against an older implementation of the library.
+ LDFLAGS-tst-sonamemove-linkmod1.so = \
+ -Wl,--version-script=tst-sonamemove-linkmod1.map \
+diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
+index 19de5de067a5ef07..7a84b1fa8c3a7fdd 100644
+--- a/elf/dl-reloc.c
++++ b/elf/dl-reloc.c
+@@ -178,12 +178,28 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+ int skip_ifunc = reloc_mode & __RTLD_NOIFUNC;
+
+ #ifdef SHARED
++ bool consider_symbind = false;
+ /* If we are auditing, install the same handlers we need for profiling. */
+ if ((reloc_mode & __RTLD_AUDIT) == 0)
+- consider_profiling |= GLRO(dl_audit) != NULL;
++ {
++ struct audit_ifaces *afct = GLRO(dl_audit);
++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
++ {
++ /* Profiling is needed only if PLT hooks are provided. */
++ if (afct->ARCH_LA_PLTENTER != NULL
++ || afct->ARCH_LA_PLTEXIT != NULL)
++ consider_profiling = 1;
++ if (afct->symbind != NULL)
++ consider_symbind = true;
++
++ afct = afct->next;
++ }
++ }
+ #elif defined PROF
+ /* Never use dynamic linker profiling for gprof profiling code. */
+ # define consider_profiling 0
++#else
++# define consider_symbind 0
+ #endif
+
+ if (l->l_relocated)
+@@ -278,7 +294,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+ ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc);
+
+ #ifndef PROF
+- if (__glibc_unlikely (consider_profiling)
++ if ((consider_profiling || consider_symbind)
+ && l->l_info[DT_PLTRELSZ] != NULL)
+ {
+ /* Allocate the array which will contain the already found
+diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
+index ec0b2164825fa538..71ec65264ff780fb 100644
+--- a/elf/dl-runtime.c
++++ b/elf/dl-runtime.c
+@@ -123,6 +123,37 @@ _dl_fixup (
+ && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0))
+ value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value));
+
++#ifdef SHARED
++ /* Auditing checkpoint: we have a new binding. Provide the auditing
++ libraries the possibility to change the value and tell us whether further
++ auditing is wanted.
++ The l_reloc_result is only allocated if there is an audit module which
++ provides a la_symbind. */
++ if (l->l_reloc_result != NULL)
++ {
++ /* This is the address in the array where we store the result of previous
++ relocations. */
++ struct reloc_result *reloc_result
++ = &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))];
++ unsigned int init = atomic_load_acquire (&reloc_result->init);
++ if (init == 0)
++ {
++ _dl_audit_symbind (l, reloc_result, sym, &value, result);
++
++ /* Store the result for later runs. */
++ if (__glibc_likely (! GLRO(dl_bind_not)))
++ {
++ reloc_result->addr = value;
++ /* Guarantee all previous writes complete before init is
++ updated. See CONCURRENCY NOTES below. */
++ atomic_store_release (&reloc_result->init, 1);
++ }
++ }
++ else
++ value = reloc_result->addr;
++ }
++#endif
++
+ /* Finally, fix up the plt itself. */
+ if (__glibc_unlikely (GLRO(dl_bind_not)))
+ return value;
+diff --git a/elf/rtld.c b/elf/rtld.c
+index 767acd122262b824..2994578ba3a5f911 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -1027,13 +1027,7 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
+ "la_objsearch\0"
+ "la_objopen\0"
+ "la_preinit\0"
+-#if __ELF_NATIVE_CLASS == 32
+- "la_symbind32\0"
+-#elif __ELF_NATIVE_CLASS == 64
+- "la_symbind64\0"
+-#else
+-# error "__ELF_NATIVE_CLASS must be defined"
+-#endif
++ LA_SYMBIND "\0"
+ #define STRING(s) __STRING (s)
+ "la_" STRING (ARCH_LA_PLTENTER) "\0"
+ "la_" STRING (ARCH_LA_PLTEXIT) "\0"
+diff --git a/elf/tst-audit19a.c b/elf/tst-audit19a.c
+new file mode 100644
+index 0000000000000000..035cde9351c2711b
+--- /dev/null
++++ b/elf/tst-audit19a.c
+@@ -0,0 +1,38 @@
++/* Check if DT_AUDIT a module without la_plt{enter,exit} symbols does not incur
++ in profiling (BZ#15533).
++ Copyright (C) 2021 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
++ . */
++
++#include
++#include
++#include
++
++static int
++do_test (void)
++{
++ void *h = xdlopen ("tst-auditmod19a.so", RTLD_NOW);
++
++ struct link_map *lmap;
++ TEST_VERIFY_EXIT (dlinfo (h, RTLD_DI_LINKMAP, &lmap) == 0);
++
++ /* The internal array is only allocated if profiling is enabled. */
++ TEST_VERIFY (lmap->l_reloc_result == NULL);
++
++ return 0;
++}
++
++#include
+diff --git a/elf/tst-audit19b.c b/elf/tst-audit19b.c
+new file mode 100644
+index 0000000000000000..da015734f24e0d79
+--- /dev/null
++++ b/elf/tst-audit19b.c
+@@ -0,0 +1,94 @@
++/* Check if DT_AUDIT a module with la_plt{enter,exit} call la_symbind
++ for lazy resolution.
++ Copyright (C) 2021 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
++ . */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++static int restart;
++#define CMDLINE_OPTIONS \
++ { "restart", no_argument, &restart, 1 },
++
++int tst_audit18bmod1_func (void);
++
++static int
++handle_restart (void)
++{
++ TEST_COMPARE (tst_audit18bmod1_func (), 10);
++ return 0;
++}
++
++static inline bool
++startswith (const char *str, const char *pre)
++{
++ size_t lenpre = strlen (pre);
++ size_t lenstr = strlen (str);
++ return lenstr < lenpre ? false : memcmp (pre, str, lenpre) == 0;
++}
++
++static int
++do_test (int argc, char *argv[])
++{
++ /* We must have either:
++ - One our fource parameters left if called initially:
++ + path to ld.so optional
++ + "--library-path" optional
++ + the library path optional
++ + the application name */
++
++ if (restart)
++ return handle_restart ();
++
++ char *spargv[9];
++ int i = 0;
++ for (; i < argc - 1; i++)
++ spargv[i] = argv[i + 1];
++ spargv[i++] = (char *) "--direct";
++ spargv[i++] = (char *) "--restart";
++ spargv[i] = NULL;
++
++ setenv ("LD_AUDIT", "tst-auditmod18b.so", 0);
++ struct support_capture_subprocess result
++ = support_capture_subprogram (spargv[0], spargv);
++ support_capture_subprocess_check (&result, "tst-audit18b", 0, sc_allow_stderr);
++
++ bool find_symbind = false;
++
++ FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
++ TEST_VERIFY (out != NULL);
++ char *buffer = NULL;
++ size_t buffer_length = 0;
++ while (xgetline (&buffer, &buffer_length, out))
++ if (startswith (buffer, "la_symbind: tst_audit18bmod1_func") == 0)
++ find_symbind = true;
++
++ TEST_COMPARE (find_symbind, true);
++
++ free (buffer);
++ xfclose (out);
++
++ return 0;
++}
++
++#define TEST_FUNCTION_ARGV do_test
++#include
+diff --git a/elf/tst-audit19bmod.c b/elf/tst-audit19bmod.c
+new file mode 100644
+index 0000000000000000..9ffdcd8f3ffbc38e
+--- /dev/null
++++ b/elf/tst-audit19bmod.c
+@@ -0,0 +1,23 @@
++/* Extra module for tst-audit18b.
++ Copyright (C) 2021 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
++ . */
++
++int
++tst_audit18bmod1_func (void)
++{
++ return 10;
++}
+diff --git a/elf/tst-auditmod19a.c b/elf/tst-auditmod19a.c
+new file mode 100644
+index 0000000000000000..f58204099457743d
+--- /dev/null
++++ b/elf/tst-auditmod19a.c
+@@ -0,0 +1,25 @@
++/* Audit module for tst-audit18a.
++ Copyright (C) 2021 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
++ . */
++
++#include
++
++unsigned int
++la_version (unsigned int version)
++{
++ return LAV_CURRENT;
++}
+diff --git a/elf/tst-auditmod19b.c b/elf/tst-auditmod19b.c
+new file mode 100644
+index 0000000000000000..e2248b2a75946746
+--- /dev/null
++++ b/elf/tst-auditmod19b.c
+@@ -0,0 +1,46 @@
++/* Audit module for tst-audit18b.
++ Copyright (C) 2021 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
++ . */
++
++#include
++#include
++#include
++
++unsigned int
++la_version (unsigned int version)
++{
++ return LAV_CURRENT;
++}
++
++unsigned int
++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
++{
++ return LA_FLG_BINDTO | LA_FLG_BINDFROM;
++}
++
++uintptr_t
++#if __ELF_NATIVE_CLASS == 32
++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
++ uintptr_t *defcook, unsigned int *flags, const char *symname)
++#else
++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
++ uintptr_t *defcook, unsigned int *flags, const char *symname)
++#endif
++{
++ fprintf (stderr, "la_symbind: %s\n", symname);
++ return sym->st_value;
++}
+diff --git a/include/link.h b/include/link.h
+index cdd011f59445e490..dd491989beb41353 100644
+--- a/include/link.h
++++ b/include/link.h
+@@ -353,8 +353,10 @@ struct link_map
+
+ #if __ELF_NATIVE_CLASS == 32
+ # define symbind symbind32
++# define LA_SYMBIND "la_symbind32"
+ #elif __ELF_NATIVE_CLASS == 64
+ # define symbind symbind64
++# define LA_SYMBIND "la_symbind64"
+ #else
+ # error "__ELF_NATIVE_CLASS must be defined"
+ #endif
diff --git a/glibc-rh2047981-24.patch b/glibc-rh2047981-24.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c6fc26a5fff3f01684d372f65309d564f735ce0f
--- /dev/null
+++ b/glibc-rh2047981-24.patch
@@ -0,0 +1,296 @@
+Added $(libdl) to $(objpfx)tst-audit-tlsdesc-dlopen in elf/Makefile
+since we still need $(libdl) in RHEL8.
+
+commit d1b38173c9255b1a4ae00018ad9b35404a7c74d0
+Author: Adhemerval Zanella
+Date: Wed Jun 30 15:51:31 2021 -0300
+
+ elf: Add audit tests for modules with TLSDESC
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 0cc03ffe2984ee50..d8d9734df0fea9a8 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -375,6 +375,22 @@ 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
++
++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) $(libdl)
++$(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
+diff --git a/elf/tst-audit-tlsdesc-dlopen.c b/elf/tst-audit-tlsdesc-dlopen.c
+new file mode 100644
+index 0000000000000000..9c16bb087aca1b77
+--- /dev/null
++++ b/elf/tst-audit-tlsdesc-dlopen.c
+@@ -0,0 +1,67 @@
++/* DT_AUDIT with modules with TLSDESC.
++ Copyright (C) 2021 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
++ . */
++
++#include
++#include
++#include
++
++static void *
++thr_func (void *mod)
++{
++ int* (*get_global1)(void) = xdlsym (mod, "get_global1");
++ int* (*get_global2)(void) = xdlsym (mod, "get_global2");
++ void (*set_global2)(int) = xdlsym (mod, "set_global2");
++ int* (*get_local1)(void) = xdlsym (mod, "get_local1");
++ int* (*get_local2)(void) = xdlsym (mod, "get_local2");
++
++ int *global1 = get_global1 ();
++ TEST_COMPARE (*global1, 0);
++ ++*global1;
++
++ int *global2 = get_global2 ();
++ TEST_COMPARE (*global2, 0);
++ ++*global2;
++ TEST_COMPARE (*global2, 1);
++
++ set_global2 (10);
++ TEST_COMPARE (*global2, 10);
++
++ int *local1 = get_local1 ();
++ TEST_COMPARE (*local1, 0);
++ ++*local1;
++
++ int *local2 = get_local2 ();
++ TEST_COMPARE (*local2, 0);
++ ++*local2;
++
++ return 0;
++}
++
++static int
++do_test (void)
++{
++ void *mod = xdlopen ("tst-audit-tlsdesc-mod1.so", RTLD_LAZY);
++
++ pthread_t thr = xpthread_create (NULL, thr_func, mod);
++ void *r = xpthread_join (thr);
++ TEST_VERIFY (r == NULL);
++
++ return 0;
++}
++
++#include
+diff --git a/elf/tst-audit-tlsdesc-mod1.c b/elf/tst-audit-tlsdesc-mod1.c
+new file mode 100644
+index 0000000000000000..61c7dd99a2fb5e28
+--- /dev/null
++++ b/elf/tst-audit-tlsdesc-mod1.c
+@@ -0,0 +1,41 @@
++/* DT_AUDIT with modules with TLSDESC.
++ Copyright (C) 2021 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
++ . */
++
++__thread int global1;
++
++int *
++get_global1 (void)
++{
++ return &global1;
++}
++
++static __thread int local1;
++
++void *
++get_local1 (void)
++{
++ return &local1;
++}
++
++extern __thread int global2;
++
++void
++set_global2 (int v)
++{
++ global2 = v;
++}
+diff --git a/elf/tst-audit-tlsdesc-mod2.c b/elf/tst-audit-tlsdesc-mod2.c
+new file mode 100644
+index 0000000000000000..28aef635f688ee03
+--- /dev/null
++++ b/elf/tst-audit-tlsdesc-mod2.c
+@@ -0,0 +1,33 @@
++/* DT_AUDIT with modules with TLSDESC.
++ Copyright (C) 2021 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
++ . */
++
++__thread int global2;
++
++int *
++get_global2 (void)
++{
++ return &global2;
++}
++
++static __thread int local2;
++
++void *
++get_local2 (void)
++{
++ return &local2;
++}
+diff --git a/elf/tst-audit-tlsdesc.c b/elf/tst-audit-tlsdesc.c
+new file mode 100644
+index 0000000000000000..3c8be81c95528f47
+--- /dev/null
++++ b/elf/tst-audit-tlsdesc.c
+@@ -0,0 +1,60 @@
++/* DT_AUDIT with modules with TLSDESC.
++ Copyright (C) 2021 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
++ . */
++
++#include
++#include
++
++extern __thread int global1;
++extern __thread int global2;
++void *get_local1 (void);
++void set_global2 (int v);
++void *get_local2 (void);
++
++static void *
++thr_func (void *clousure)
++{
++ TEST_COMPARE (global1, 0);
++ ++global1;
++ TEST_COMPARE (global2, 0);
++ ++global2;
++ TEST_COMPARE (global2, 1);
++
++ set_global2 (10);
++ TEST_COMPARE (global2, 10);
++
++ int *local1 = get_local1 ();
++ TEST_COMPARE (*local1, 0);
++ ++*local1;
++
++ int *local2 = get_local2 ();
++ TEST_COMPARE (*local2, 0);
++ ++*local2;
++
++ return 0;
++}
++
++static int
++do_test (void)
++{
++ pthread_t thr = xpthread_create (NULL, thr_func, NULL);
++ void *r = xpthread_join (thr);
++ TEST_VERIFY (r == NULL);
++ return 0;
++}
++
++#include
+diff --git a/elf/tst-auditmod-tlsdesc.c b/elf/tst-auditmod-tlsdesc.c
+new file mode 100644
+index 0000000000000000..e4b835d1f1fb6f73
+--- /dev/null
++++ b/elf/tst-auditmod-tlsdesc.c
+@@ -0,0 +1,25 @@
++/* DT_AUDIT with modules with TLSDESC.
++ Copyright (C) 2021 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
++ . */
++
++#include
++
++unsigned int
++la_version (unsigned int version)
++{
++ return LAV_CURRENT;
++}
diff --git a/glibc-rh2047981-25.patch b/glibc-rh2047981-25.patch
new file mode 100644
index 0000000000000000000000000000000000000000..14cbb8d19b60e343a031fe3df7200a00a94a8d7d
--- /dev/null
+++ b/glibc-rh2047981-25.patch
@@ -0,0 +1,313 @@
+commit f0e23d34a7bdf6b90fba954ee741419171ac41b2
+Author: Adhemerval Zanella
+Date: Mon Jul 19 18:42:26 2021 -0300
+
+ elf: Issue audit la_objopen for vDSO
+
+ The vDSO is is listed in the link_map chain, but is never the subject of
+ an la_objopen call. A new internal flag __RTLD_VDSO is added that
+ acts as __RTLD_OPENEXEC to allocate the required 'struct auditstate'
+ extra space for the 'struct link_map'.
+
+ The return value from the callback is currently ignored, since there
+ is no PLT call involved by glibc when using the vDSO, neither the vDSO
+ are exported directly.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+Conflicts:
+ elf/Makefile
+
+diff --git a/elf/Makefile b/elf/Makefile
+index d8d9734df0fea9a8..f047c1cce0c55da0 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -222,6 +222,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ tst-audit17 \
+ tst-audit18 \
+ tst-audit19b \
++ tst-audit22 \
+ # reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+ neededtest neededtest2 neededtest3 neededtest4 \
+@@ -363,6 +364,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ tst-auditmod19a \
+ tst-auditmod19b \
+ tst-audit19bmod \
++ tst-auditmod22 \
+
+ # Most modules build with _ISOMAC defined, but those filtered out
+ # depend on internal headers.
+@@ -1577,6 +1579,9 @@ $(objpfx)tst-audit19b.out: $(objpfx)tst-auditmod19b.so
+ $(objpfx)tst-audit19b: $(objpfx)tst-audit19bmod.so
+ tst-audit19b-ARGS = -- $(host-test-program-cmd)
+
++$(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so
++tst-audit22-ARGS = -- $(host-test-program-cmd)
++
+ # tst-sonamemove links against an older implementation of the library.
+ LDFLAGS-tst-sonamemove-linkmod1.so = \
+ -Wl,--version-script=tst-sonamemove-linkmod1.map \
+diff --git a/elf/dl-object.c b/elf/dl-object.c
+index 05a7750c65305771..3be309ecf1b5d4e2 100644
+--- a/elf/dl-object.c
++++ b/elf/dl-object.c
+@@ -59,16 +59,19 @@ _dl_new_object (char *realname, const char *libname, int type,
+ {
+ #ifdef SHARED
+ unsigned int naudit;
+- if (__glibc_unlikely ((mode & __RTLD_OPENEXEC) != 0))
++ if (__glibc_unlikely ((mode & (__RTLD_OPENEXEC | __RTLD_VDSO)) != 0))
+ {
+- assert (type == lt_executable);
+- assert (nsid == LM_ID_BASE);
++ if (mode & __RTLD_OPENEXEC)
++ {
++ assert (type == lt_executable);
++ assert (nsid == LM_ID_BASE);
+
+- /* Ignore the specified libname for the main executable. It is
+- only known with an explicit loader invocation. */
+- libname = "";
++ /* Ignore the specified libname for the main executable. It is
++ only known with an explicit loader invocation. */
++ libname = "";
++ }
+
+- /* We create the map for the executable before we know whether
++ /* We create the map for the executable and vDSO before we know whether
+ we have auditing libraries and if yes, how many. Assume the
+ worst. */
+ naudit = DL_NNS;
+diff --git a/elf/rtld.c b/elf/rtld.c
+index 2994578ba3a5f911..efcbeac6c24c4b7b 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -1917,6 +1917,12 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
+ assert (i == npreloads);
+ }
+
++#ifdef NEED_DL_SYSINFO_DSO
++ /* Now that the audit modules are opened, call la_objopen for the vDSO. */
++ if (GLRO(dl_sysinfo_map) != NULL)
++ _dl_audit_objopen (GLRO(dl_sysinfo_map), LM_ID_BASE);
++#endif
++
+ /* Load all the libraries specified by DT_NEEDED entries. If LD_PRELOAD
+ specified some libraries to load, these are inserted before the actual
+ dependencies in the executable's searchlist for symbol resolution. */
+diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h
+index 34b1d5e8c37c2610..d2b35a080b57c183 100644
+--- a/elf/setup-vdso.h
++++ b/elf/setup-vdso.h
+@@ -30,7 +30,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
+ We just want our data structures to describe it as if we had just
+ mapped and relocated it normally. */
+ struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL,
+- 0, LM_ID_BASE);
++ __RTLD_VDSO, LM_ID_BASE);
+ if (__glibc_likely (l != NULL))
+ {
+ static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
+diff --git a/elf/tst-audit22.c b/elf/tst-audit22.c
+new file mode 100644
+index 0000000000000000..18fd22a760ddc3d8
+--- /dev/null
++++ b/elf/tst-audit22.c
+@@ -0,0 +1,124 @@
++/* Check DTAUDIT and vDSO interaction.
++ Copyright (C) 2021 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
++ . */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++static int restart;
++#define CMDLINE_OPTIONS \
++ { "restart", no_argument, &restart, 1 },
++
++static uintptr_t vdso_addr;
++
++static int
++handle_restart (void)
++{
++ fprintf (stderr, "vdso: %p\n", (void*) vdso_addr);
++ return 0;
++}
++
++static uintptr_t
++parse_address (const char *str)
++{
++ void *r;
++ TEST_COMPARE (sscanf (str, "%p\n", &r), 1);
++ return (uintptr_t) r;
++}
++
++static inline bool
++startswith (const char *str, const char *pre)
++{
++ size_t lenpre = strlen (pre);
++ size_t lenstr = strlen (str);
++ return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0;
++}
++
++static int
++do_test (int argc, char *argv[])
++{
++ vdso_addr = getauxval (AT_SYSINFO_EHDR);
++ if (vdso_addr == 0)
++ FAIL_UNSUPPORTED ("getauxval (AT_SYSINFO_EHDR) returned 0");
++
++ /* We must have either:
++ - One our fource parameters left if called initially:
++ + path to ld.so optional
++ + "--library-path" optional
++ + the library path optional
++ + the application name */
++ if (restart)
++ return handle_restart ();
++
++ char *spargv[9];
++ int i = 0;
++ for (; i < argc - 1; i++)
++ spargv[i] = argv[i + 1];
++ spargv[i++] = (char *) "--direct";
++ spargv[i++] = (char *) "--restart";
++ spargv[i] = NULL;
++
++ setenv ("LD_AUDIT", "tst-auditmod22.so", 0);
++ struct support_capture_subprocess result
++ = support_capture_subprogram (spargv[0], spargv);
++ support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr);
++
++ /* The respawned process should always print the vDSO address (otherwise it
++ will fails as unsupported). However, on some architectures the audit
++ module might see the vDSO with l_addr being 0, meaning a fixed mapping
++ (linux-gate.so). In this case we don't check its value against
++ AT_SYSINFO_EHDR one. */
++ uintptr_t vdso_process = 0;
++ bool vdso_audit_found = false;
++ uintptr_t vdso_audit = 0;
++
++ FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
++ TEST_VERIFY (out != NULL);
++ char *buffer = NULL;
++ size_t buffer_length = 0;
++ while (xgetline (&buffer, &buffer_length, out))
++ {
++ if (startswith (buffer, "vdso: "))
++ vdso_process = parse_address (buffer + strlen ("vdso: "));
++ else if (startswith (buffer, "vdso found: "))
++ {
++ vdso_audit = parse_address (buffer + strlen ("vdso found: "));
++ vdso_audit_found = true;
++ }
++ }
++
++ TEST_COMPARE (vdso_audit_found, true);
++ if (vdso_audit != 0)
++ TEST_COMPARE (vdso_process, vdso_audit);
++
++ free (buffer);
++ xfclose (out);
++
++ return 0;
++}
++
++#define TEST_FUNCTION_ARGV do_test
++#include
+diff --git a/elf/tst-auditmod22.c b/elf/tst-auditmod22.c
+new file mode 100644
+index 0000000000000000..8e05ce8cbb215dd5
+--- /dev/null
++++ b/elf/tst-auditmod22.c
+@@ -0,0 +1,51 @@
++/* Check DTAUDIT and vDSO interaction.
++ Copyright (C) 2021 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
++ . */
++
++#include
++#include
++#include
++#include
++#include
++#include
++
++static inline bool
++startswith (const char *str, const char *pre)
++{
++ size_t lenpre = strlen (pre);
++ size_t lenstr = strlen (str);
++ return lenstr < lenpre ? false : memcmp (pre, str, lenpre) == 0;
++}
++
++unsigned int
++la_version (unsigned int version)
++{
++ return LAV_CURRENT;
++}
++
++unsigned int
++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
++{
++ /* The linux-gate.so is placed at a fixed address, thus l_addr being 0,
++ and it might be the value reported as the AT_SYSINFO_EHDR. */
++ if (map->l_addr == 0 && startswith (map->l_name, "linux-gate.so"))
++ fprintf (stderr, "vdso found: %p\n", NULL);
++ else if (map->l_addr == getauxval (AT_SYSINFO_EHDR))
++ fprintf (stderr, "vdso found: %p\n", (void*) map->l_addr);
++
++ return 0;
++}
+diff --git a/include/dlfcn.h b/include/dlfcn.h
+index 109586a1d968b630..a39cc9c69f55a56a 100644
+--- a/include/dlfcn.h
++++ b/include/dlfcn.h
+@@ -12,6 +12,8 @@
+ #define __RTLD_AUDIT 0x08000000
+ #define __RTLD_SECURE 0x04000000 /* Apply additional security checks. */
+ #define __RTLD_NOIFUNC 0x02000000 /* Suppress calling ifunc functions. */
++#define __RTLD_VDSO 0x01000000 /* Tell _dl_new_object the object is
++ system-loaded. */
+
+ #define __LM_ID_CALLER -2
+
diff --git a/glibc-rh2047981-26.patch b/glibc-rh2047981-26.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b05628f13910a9a782f94e7bab9fc37a26e08db1
--- /dev/null
+++ b/glibc-rh2047981-26.patch
@@ -0,0 +1,170 @@
+Added $(objpfx)tst-auditmod20: $(libdl) in elf/Makefile since
+we still have $(libdl) in RHEL8.
+
+commit 484e672ddabe0a919a692520e6ac8f2580866235
+Author: Adhemerval Zanella
+Date: Wed Jun 30 17:33:57 2021 -0300
+
+ elf: Do not fail for failed dlmopen on audit modules (BZ #28061)
+
+ The dl_main sets the LM_ID_BASE to RT_ADD just before starting to
+ add load new shared objects. The state is set to RT_CONSISTENT just
+ after all objects are loaded.
+
+ However if a audit modules tries to dlmopen an inexistent module,
+ the _dl_open will assert that the namespace is in an inconsistent
+ state.
+
+ This is different than dlopen, since first it will not use
+ LM_ID_BASE and second _dl_map_object_from_fd is the sole responsible
+ to set and reset the r_state value.
+
+ So the assert on _dl_open can not really be seen if the state is
+ consistent, since _dt_main resets it. This patch removes the assert.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Florian Weimer
+
+Conflicts:
+ elf/dl-open.c
+ Uses dl_debug_initialize instead of dl_debug_update.
+
+diff --git a/elf/Makefile b/elf/Makefile
+index f047c1cce0c55da0..7c7b9e1937d3e41c 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -222,6 +222,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ tst-audit17 \
+ tst-audit18 \
+ tst-audit19b \
++ tst-audit20 \
+ tst-audit22 \
+ # reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+@@ -364,6 +365,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ tst-auditmod19a \
+ tst-auditmod19b \
+ tst-audit19bmod \
++ tst-auditmod20 \
+ tst-auditmod22 \
+
+ # Most modules build with _ISOMAC defined, but those filtered out
+@@ -1579,6 +1581,10 @@ $(objpfx)tst-audit19b.out: $(objpfx)tst-auditmod19b.so
+ $(objpfx)tst-audit19b: $(objpfx)tst-audit19bmod.so
+ tst-audit19b-ARGS = -- $(host-test-program-cmd)
+
++$(objpfx)tst-audit20.out: $(objpfx)tst-auditmod20.so
++tst-audit20-ENV = LD_AUDIT=$(objpfx)tst-auditmod20.so
++$(objpfx)tst-auditmod20.so: $(libdl)
++
+ $(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so
+ tst-audit22-ARGS = -- $(host-test-program-cmd)
+
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index 660a56b2fb2639cd..6b85e9ab4e249f86 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -911,8 +911,6 @@ no more namespaces available for dlmopen()"));
+ the flag here. */
+ }
+
+- assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
+-
+ /* Release the lock. */
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+diff --git a/elf/tst-audit20.c b/elf/tst-audit20.c
+new file mode 100644
+index 0000000000000000..6f39ccee865b012b
+--- /dev/null
++++ b/elf/tst-audit20.c
+@@ -0,0 +1,25 @@
++/* Check dlopen failure on audit modules.
++ Copyright (C) 2021 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
++ . */
++
++static int
++do_test (void)
++{
++ return 0;
++}
++
++#include
+diff --git a/elf/tst-auditmod20.c b/elf/tst-auditmod20.c
+new file mode 100644
+index 0000000000000000..c57e50ee4e88dd6b
+--- /dev/null
++++ b/elf/tst-auditmod20.c
+@@ -0,0 +1,57 @@
++/* Check dlopen failure on audit modules.
++ Copyright (C) 2021 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
++ . */
++
++#include
++#include
++#include
++
++unsigned int
++la_version (unsigned int v)
++{
++ return LAV_CURRENT;
++}
++
++static void
++check (void)
++{
++ {
++ void *mod = dlopen ("nonexistent.so", RTLD_NOW);
++ if (mod != NULL)
++ abort ();
++ }
++
++ {
++ void *mod = dlmopen (LM_ID_BASE, "nonexistent.so", RTLD_NOW);
++ if (mod != NULL)
++ abort ();
++ }
++}
++
++void
++la_activity (uintptr_t *cookie, unsigned int flag)
++{
++ if (flag != LA_ACT_CONSISTENT)
++ return;
++ check ();
++}
++
++void
++la_preinit (uintptr_t *cookie)
++{
++ check ();
++}
diff --git a/glibc-rh2047981-27.patch b/glibc-rh2047981-27.patch
new file mode 100644
index 0000000000000000000000000000000000000000..08f14489d08ebf1d381c17c9105c13c2a43f8319
--- /dev/null
+++ b/glibc-rh2047981-27.patch
@@ -0,0 +1,557 @@
+commit 28713c06129f8f64f88c423266e6ff2880216509
+Author: H.J. Lu
+Date: Mon Dec 13 09:43:52 2021 -0800
+
+ elf: Sort tests and modules-names
+
+ Sort tests and modules-names to reduce future conflicts.
+
+Conflicts:
+ elf/Makefile
+ Complete rewrite of sorted lists.
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 7c7b9e1937d3e41c..914cb5ad2f2c3aea 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -185,46 +185,130 @@ tests-static += tst-tls9-static
+ tst-tls9-static-ENV = \
+ LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn
+
+-tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+- constload1 order noload filter \
+- reldep reldep2 reldep3 reldep4 nodelete nodelete2 \
+- nodlopen nodlopen2 lateglobal initfirst global \
+- restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
+- tst-tls4 tst-tls5 \
+- tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
+- tst-tls16 tst-tls17 tst-tls18 tst-tls19 tst-tls-dlinfo \
+- tst-align tst-align2 \
+- tst-dlmodcount tst-dlopenrpath tst-deep1 \
+- tst-dlmopen1 tst-dlmopen3 \
+- unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
+- tst-audit1 tst-audit2 tst-audit8 tst-audit9 \
+- tst-addr1 tst-thrlock \
+- tst-unique1 tst-unique2 $(if $(CXX),tst-unique3 tst-unique4 \
+- tst-nodelete tst-dlopen-nodelete-reloc) \
+- tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
+- tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
+- tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
+- tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
+- tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
+- tst-audit13 \
+- tst-sonamemove-link tst-sonamemove-dlopen \
+- tst-auditmany tst-initfinilazyfail \
+- tst-dlopenfail tst-dlopenfail-2 \
+- tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \
+- tst-audit14 tst-audit15 tst-audit16 \
+- tst-tls-ie tst-tls-ie-dlmopen \
+- argv0test \
+- tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \
+- tst-tls20 tst-tls21 \
+- tst-rtld-run-static \
+- tst-dlmopen-dlerror \
+- tst-dlmopen-gethostbyname \
+- tst-audit17 \
+- tst-audit18 \
+- tst-audit19b \
+- tst-audit20 \
+- tst-audit22 \
++tests += \
++ argv0test \
++ constload1 \
++ dblload \
++ dblunload \
++ filter \
++ global \
++ initfirst \
++ lateglobal \
++ loadfail \
++ multiload \
++ next \
++ nodelete \
++ nodelete2 \
++ nodlopen \
++ nodlopen2 \
++ noload \
++ order \
++ order2 \
++ origtest \
++ preloadtest \
++ reldep \
++ reldep2 \
++ reldep3 \
++ reldep4 \
++ reldep5 \
++ reldep6 \
++ reldep7 \
++ reldep8 \
++ resolvfail \
++ restest1 \
++ restest2 \
++ tst-absolute-sym \
++ tst-absolute-zero \
++ tst-addr1 \
++ tst-align \
++ tst-align2 \
++ tst-audit1 \
++ tst-audit11 \
++ tst-audit12 \
++ tst-audit13 \
++ tst-audit14 \
++ tst-audit15 \
++ tst-audit16 \
++ tst-audit17 \
++ tst-audit18 \
++ tst-audit19b \
++ tst-audit2 \
++ tst-audit20 \
++ tst-audit22 \
++ tst-audit8 \
++ tst-audit9 \
++ tst-auditmany \
++ tst-auxobj \
++ tst-auxobj-dlopen \
++ tst-big-note \
++ tst-debug1 \
++ tst-deep1 \
++ tst-dlmodcount \
++ tst-dlmopen1 \
++ tst-dlmopen3 \
++ tst-dlmopen-dlerror \
++ tst-dlmopen-gethostbyname \
++ tst-dlopenfail \
++ tst-dlopenfail-2 \
++ tst-dlopenrpath \
++ tst-dlsym-error \
++ tst-filterobj \
++ tst-filterobj-dlopen \
++ tst-glibc-hwcaps \
++ tst-glibc-hwcaps-mask \
++ tst-glibc-hwcaps-prepend \
++ tst-global1 \
++ tst-initfinilazyfail \
++ tst-initorder \
++ tst-initorder2 \
++ tst-latepthread \
++ tst-main1 \
++ tst-nodelete2 \
++ tst-nodelete-dlclose \
++ tst-nodelete-opened \
++ tst-noload \
++ tst-null-argv \
++ tst-relsort1 \
++ tst-rtld-run-static \
++ tst-sonamemove-dlopen \
++ tst-sonamemove-link \
++ tst-thrlock \
++ tst-tls10 \
++ tst-tls11 \
++ tst-tls12 \
++ tst-tls13 \
++ tst-tls14 \
++ tst-tls15 \
++ tst-tls16 \
++ tst-tls17 \
++ tst-tls18 \
++ tst-tls19 \
++ tst-tls20 \
++ tst-tls21 \
++ tst-tls4 \
++ tst-tls5 \
++ tst-tlsalign \
++ tst-tlsalign-extern \
++ tst-tls-dlinfo \
++ tst-tls-ie \
++ tst-tls-ie-dlmopen \
++ tst-tls-manydynamic \
++ tst-unique1 \
++ tst-unique2 \
++ unload3 \
++ unload4 \
++ unload5 \
++ unload6 \
++ unload7 \
++ unload8 \
+ # reldep9
++tests-cxx = \
++ tst-dlopen-nodelete-reloc \
++ tst-nodelete \
++ tst-unique3 \
++ tst-unique4 \
++
++tests += $(if $(CXX),$(tests-cxx))
+ tests-internal += loadtest unload unload2 circleload1 \
+ neededtest neededtest2 neededtest3 neededtest4 \
+ tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
+@@ -266,107 +350,269 @@ tst-tls-many-dynamic-modules-dep-bad = \
+ extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os) \
+ tst-tlsalign-vars.o
+ test-extras += tst-tlsmod17a tst-tlsmod18a tst-tlsalign-vars
+-modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+- testobj1_1 failobj constload2 constload3 unloadmod \
+- dep1 dep2 dep3 dep4 vismod1 vismod2 vismod3 \
+- nodelmod1 nodelmod2 nodelmod3 nodelmod4 \
+- nodel2mod1 nodel2mod2 nodel2mod3 \
+- nodlopenmod nodlopenmod2 filtmod1 filtmod2 \
+- reldepmod1 reldepmod2 reldepmod3 reldepmod4 nextmod1 nextmod2 \
+- reldep4mod1 reldep4mod2 reldep4mod3 reldep4mod4 \
+- neededobj1 neededobj2 neededobj3 neededobj4 \
+- neededobj5 neededobj6 firstobj globalmod1 \
+- unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj \
+- dblloadmod1 dblloadmod2 dblloadmod3 reldepmod5 reldepmod6 \
+- reldep6mod0 reldep6mod1 reldep6mod2 reldep6mod3 reldep6mod4 \
+- reldep7mod1 reldep7mod2 \
+- tst-tlsmod1 tst-tlsmod2 tst-tlsmod3 tst-tlsmod4 \
+- tst-tlsmod5 tst-tlsmod6 tst-tlsmod7 tst-tlsmod8 \
+- tst-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \
+- tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \
+- tst-tlsmod15a tst-tlsmod15b tst-tlsmod16a tst-tlsmod16b \
+- $(tlsmod17a-modules) tst-tlsmod17b $(tlsmod18a-modules) \
+- tst-tls19mod1 tst-tls19mod2 tst-tls19mod3 \
+- circlemod1 circlemod1a circlemod2 circlemod2a \
+- circlemod3 circlemod3a \
+- reldep8mod1 reldep8mod2 reldep8mod3 \
+- reldep9mod1 reldep9mod2 reldep9mod3 \
+- tst-alignmod tst-alignmod2 \
+- $(modules-execstack-$(have-z-execstack)) \
+- tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
+- tst-dlmopen1mod tst-auditmod1 \
+- unload3mod1 unload3mod2 unload3mod3 unload3mod4 \
+- unload4mod1 unload4mod2 unload4mod3 unload4mod4 \
+- unload6mod1 unload6mod2 unload6mod3 \
+- unload7mod1 unload7mod2 \
+- unload8mod1 unload8mod1x unload8mod2 unload8mod3 \
+- order2mod1 order2mod2 order2mod3 order2mod4 \
+- tst-unique1mod1 tst-unique1mod2 \
+- tst-unique2mod1 tst-unique2mod2 \
+- tst-auditmod9a tst-auditmod9b \
+- $(if $(CXX),tst-unique3lib tst-unique3lib2 tst-unique4lib \
+- tst-nodelete-uniquemod tst-nodelete-rtldmod \
+- tst-nodelete-zmod \
+- tst-dlopen-nodelete-reloc-mod1 \
+- tst-dlopen-nodelete-reloc-mod2 \
+- tst-dlopen-nodelete-reloc-mod3 \
+- tst-dlopen-nodelete-reloc-mod4 \
+- tst-dlopen-nodelete-reloc-mod5 \
+- tst-dlopen-nodelete-reloc-mod6 \
+- tst-dlopen-nodelete-reloc-mod7 \
+- tst-dlopen-nodelete-reloc-mod8 \
+- tst-dlopen-nodelete-reloc-mod9 \
+- tst-dlopen-nodelete-reloc-mod10 \
+- tst-dlopen-nodelete-reloc-mod11 \
+- tst-dlopen-nodelete-reloc-mod12 \
+- tst-dlopen-nodelete-reloc-mod13 \
+- tst-dlopen-nodelete-reloc-mod14 \
+- tst-dlopen-nodelete-reloc-mod15 \
+- tst-dlopen-nodelete-reloc-mod16 \
+- tst-dlopen-nodelete-reloc-mod17) \
+- tst-initordera1 tst-initorderb1 \
+- tst-initordera2 tst-initorderb2 \
+- tst-initordera3 tst-initordera4 \
+- tst-initorder2a tst-initorder2b tst-initorder2c \
+- tst-initorder2d \
+- tst-relsort1mod1 tst-relsort1mod2 tst-array2dep \
+- tst-array5dep tst-null-argv-lib \
+- tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \
+- tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \
+- tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \
+- tst-latepthreadmod $(tst-tls-many-dynamic-modules) \
+- $(tst-tls-many-dynamic-modules-dep) \
+- $(tst-tls-many-dynamic-modules-dep-bad) \
+- tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \
+- tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \
+- tst-absolute-zero-lib tst-big-note-lib \
+- tst-audit13mod1 tst-sonamemove-linkmod1 \
+- tst-sonamemove-runmod1 tst-sonamemove-runmod2 \
+- tst-auditmanymod1 tst-auditmanymod2 tst-auditmanymod3 \
+- tst-auditmanymod4 tst-auditmanymod5 tst-auditmanymod6 \
+- tst-auditmanymod7 tst-auditmanymod8 tst-auditmanymod9 \
+- tst-initlazyfailmod tst-finilazyfailmod \
+- tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \
+- tst-dlopenfailmod3 \
+- tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee \
+- tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3 \
+- tst-tls-ie-mod0 tst-tls-ie-mod1 tst-tls-ie-mod2 \
+- tst-tls-ie-mod3 tst-tls-ie-mod4 tst-tls-ie-mod5 \
+- tst-tls-ie-mod6 libmarkermod1-1 libmarkermod1-2 libmarkermod1-3 \
+- libmarkermod2-1 libmarkermod2-2 \
+- libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \
+- libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \
+- libmarkermod5-1 libmarkermod5-2 libmarkermod5-3 libmarkermod5-4 \
+- libmarkermod5-5 tst-tls20mod-bad tst-tls21mod \
+- tst-dlmopen-dlerror-mod \
+- tst-dlmopen-gethostbyname-mod \
+- tst-auditmod18 \
+- tst-audit18mod \
+- tst-auditmod19a \
+- tst-auditmod19b \
+- tst-audit19bmod \
+- tst-auditmod20 \
+- tst-auditmod22 \
++modules-names = \
++ circlemod1 \
++ circlemod1a \
++ circlemod2 \
++ circlemod2a \
++ circlemod3 \
++ circlemod3a \
++ constload2 \
++ constload3 \
++ dblloadmod1 \
++ dblloadmod2 \
++ dblloadmod3 \
++ dep1 \
++ dep2 \
++ dep3 \
++ dep4 \
++ failobj \
++ filtmod1 \
++ filtmod2 \
++ firstobj \
++ globalmod1 \
++ libmarkermod1-1 \
++ libmarkermod1-2 \
++ libmarkermod1-3 \
++ libmarkermod2-1 \
++ libmarkermod2-2 \
++ libmarkermod3-1 \
++ libmarkermod3-2 \
++ libmarkermod3-3 \
++ libmarkermod4-1 \
++ libmarkermod4-2 \
++ libmarkermod4-3 \
++ libmarkermod4-4 \
++ libmarkermod5-1 \
++ libmarkermod5-2 \
++ libmarkermod5-3 \
++ libmarkermod5-4 \
++ libmarkermod5-5 \
++ ltglobmod1 \
++ ltglobmod2 \
++ neededobj1 \
++ neededobj2 \
++ neededobj3 \
++ neededobj4 \
++ neededobj5 \
++ neededobj6 \
++ nextmod1 \
++ nextmod2 \
++ nodel2mod1 \
++ nodel2mod2 \
++ nodel2mod3 \
++ nodelmod1 \
++ nodelmod2 \
++ nodelmod3 \
++ nodelmod4 \
++ nodlopenmod \
++ nodlopenmod2 \
++ order2mod1 \
++ order2mod2 \
++ order2mod3 \
++ order2mod4 \
++ pathoptobj \
++ reldep4mod1 \
++ reldep4mod2 \
++ reldep4mod3 \
++ reldep4mod4 \
++ reldep6mod0 \
++ reldep6mod1 \
++ reldep6mod2 \
++ reldep6mod3 \
++ reldep6mod4 \
++ reldep7mod1 \
++ reldep7mod2 \
++ reldep8mod1 \
++ reldep8mod2 \
++ reldep8mod3 \
++ reldep9mod1 \
++ reldep9mod2 \
++ reldep9mod3 \
++ reldepmod1 \
++ reldepmod2 \
++ reldepmod3 \
++ reldepmod4 \
++ reldepmod5 \
++ reldepmod6 \
++ testobj1 \
++ testobj1_1 \
++ testobj2 \
++ testobj3 \
++ testobj4 \
++ testobj5 \
++ testobj6 \
++ tst-absolute-sym-lib \
++ tst-absolute-zero-lib \
++ tst-alignmod \
++ tst-alignmod2 \
++ tst-array2dep \
++ tst-array5dep \
++ tst-audit11mod1 \
++ tst-audit11mod2 \
++ tst-audit12mod1 \
++ tst-audit12mod2 \
++ tst-audit12mod3 \
++ tst-audit13mod1 \
++ tst-audit18mod \
++ tst-audit19bmod \
++ tst-auditlogmod-1 \
++ tst-auditlogmod-2 \
++ tst-auditlogmod-3 \
++ tst-auditmanymod1 \
++ tst-auditmanymod2 \
++ tst-auditmanymod3 \
++ tst-auditmanymod4 \
++ tst-auditmanymod5 \
++ tst-auditmanymod6 \
++ tst-auditmanymod7 \
++ tst-auditmanymod8 \
++ tst-auditmanymod9 \
++ tst-auditmod1 \
++ tst-auditmod9a \
++ tst-auditmod9b \
++ tst-auditmod11 \
++ tst-auditmod12 \
++ tst-auditmod18 \
++ tst-auditmod19a \
++ tst-auditmod19b \
++ tst-auditmod20 \
++ tst-auditmod22 \
++ tst-big-note-lib \
++ tst-deep1mod1 \
++ tst-deep1mod2 \
++ tst-deep1mod3 \
++ tst-dlmopen1mod \
++ tst-dlmopen-dlerror-mod \
++ tst-dlmopen-gethostbyname-mod \
++ tst-dlopenfaillinkmod \
++ tst-dlopenfailmod1 \
++ tst-dlopenfailmod2 \
++ tst-dlopenfailmod3 \
++ tst-dlopenrpathmod \
++ tst-filterobj-aux \
++ tst-filterobj-filtee \
++ tst-filterobj-flt \
++ tst-finilazyfailmod \
++ tst-initlazyfailmod \
++ tst-initorder2a \
++ tst-initorder2b \
++ tst-initorder2c \
++ tst-initorder2d \
++ tst-initordera1 \
++ tst-initordera2 \
++ tst-initordera3 \
++ tst-initordera4 \
++ tst-initorderb1 \
++ tst-initorderb2 \
++ tst-latepthreadmod \
++ tst-libc_dlvsym-dso \
++ tst-main1mod \
++ tst-nodelete2mod \
++ tst-nodelete-dlclose-dso \
++ tst-nodelete-dlclose-plugin \
++ tst-nodelete-opened-lib \
++ tst-null-argv-lib \
++ tst-relsort1mod1 \
++ tst-relsort1mod2 \
++ tst-sonamemove-linkmod1 \
++ tst-sonamemove-runmod1 \
++ tst-sonamemove-runmod2 \
++ tst-tls19mod1 \
++ tst-tls19mod2 \
++ tst-tls19mod3 \
++ tst-tls20mod-bad \
++ tst-tls21mod \
++ tst-tlsalign-lib \
++ tst-tls-ie-mod0 \
++ tst-tls-ie-mod1 \
++ tst-tls-ie-mod2 \
++ tst-tls-ie-mod3 \
++ tst-tls-ie-mod4 \
++ tst-tls-ie-mod5 \
++ tst-tls-ie-mod6 \
++ tst-tlsmod1 \
++ tst-tlsmod10 \
++ tst-tlsmod11 \
++ tst-tlsmod12 \
++ tst-tlsmod13 \
++ tst-tlsmod13a \
++ tst-tlsmod14a \
++ tst-tlsmod14b \
++ tst-tlsmod15a \
++ tst-tlsmod15b \
++ tst-tlsmod16a \
++ tst-tlsmod16b \
++ tst-tlsmod17b \
++ tst-tlsmod2 \
++ tst-tlsmod3 \
++ tst-tlsmod4 \
++ tst-tlsmod5 \
++ tst-tlsmod6 \
++ tst-tlsmod7 \
++ tst-tlsmod8 \
++ tst-tlsmod9 \
++ tst-unique1mod1 \
++ tst-unique1mod2 \
++ tst-unique2mod1 \
++ tst-unique2mod2 \
++ unload2dep \
++ unload2mod \
++ unload3mod1 \
++ unload3mod2 \
++ unload3mod3 \
++ unload3mod4 \
++ unload4mod1 \
++ unload4mod2 \
++ unload4mod3 \
++ unload4mod4 \
++ unload6mod1 \
++ unload6mod2 \
++ unload6mod3 \
++ unload7mod1 \
++ unload7mod2 \
++ unload8mod1 \
++ unload8mod1x \
++ unload8mod2 \
++ unload8mod3 \
++ unloadmod \
++ vismod1 \
++ vismod2 \
++ vismod3 \
++
++modules-names-cxx = \
++ tst-dlopen-nodelete-reloc-mod1 \
++ tst-dlopen-nodelete-reloc-mod10 \
++ tst-dlopen-nodelete-reloc-mod11 \
++ tst-dlopen-nodelete-reloc-mod12 \
++ tst-dlopen-nodelete-reloc-mod13 \
++ tst-dlopen-nodelete-reloc-mod14 \
++ tst-dlopen-nodelete-reloc-mod15 \
++ tst-dlopen-nodelete-reloc-mod16 \
++ tst-dlopen-nodelete-reloc-mod17 \
++ tst-dlopen-nodelete-reloc-mod2 \
++ tst-dlopen-nodelete-reloc-mod3 \
++ tst-dlopen-nodelete-reloc-mod4 \
++ tst-dlopen-nodelete-reloc-mod5 \
++ tst-dlopen-nodelete-reloc-mod6 \
++ tst-dlopen-nodelete-reloc-mod7 \
++ tst-dlopen-nodelete-reloc-mod8 \
++ tst-dlopen-nodelete-reloc-mod9 \
++ tst-nodelete-rtldmod \
++ tst-nodelete-uniquemod \
++ tst-nodelete-zmod \
++ tst-unique3lib \
++ tst-unique3lib2 \
++ tst-unique4lib \
++
++modules-names += \
++ $(if $(CXX),$(modules-names-cxx)) \
++ $(modules-execstack-$(have-z-execstack)) \
++ $(tst-tls-many-dynamic-modules) \
++ $(tst-tls-many-dynamic-modules-dep) \
++ $(tst-tls-many-dynamic-modules-dep-bad) \
++ $(tlsmod17a-modules) \
++ $(tlsmod18a-modules) \
+
+ # Most modules build with _ISOMAC defined, but those filtered out
+ # depend on internal headers.
diff --git a/glibc-rh2047981-28.patch b/glibc-rh2047981-28.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9fb9d98b0f7eaecb60f79b27756602367471a5b9
--- /dev/null
+++ b/glibc-rh2047981-28.patch
@@ -0,0 +1,77 @@
+commit bfb5ed5df3dd4d9507b4922248dc445b690d19c0
+Author: H.J. Lu
+Date: Fri Oct 15 10:44:49 2021 -0700
+
+ elf: Also try DT_RUNPATH for LD_AUDIT dlopen [BZ #28455]
+
+ DT_RUNPATH is only used to find the immediate dependencies of the
+ executable or shared object containing the DT_RUNPATH entry. Update
+ LD_AUDIT dlopen call to try the DT_RUNPATH entry of the executable.
+
+ Add tst-audit14a, which is copied from tst-audit14, to DT_RUNPATH and
+ build tst-audit14 with -Wl,--disable-new-dtags to test DT_RPATH.
+
+ This partially fixes BZ #28455.
+
+Conflicts:
+ elf/Makefile
+ Rewrite test inclusion to use older stdout pattern.
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 914cb5ad2f2c3aea..4ec4e9a049156755 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -227,6 +227,7 @@ tests += \
+ tst-audit12 \
+ tst-audit13 \
+ tst-audit14 \
++ tst-audit14a \
+ tst-audit15 \
+ tst-audit16 \
+ tst-audit17 \
+@@ -1788,9 +1789,11 @@ $(objpfx)tst-auditmany.out: $(objpfx)tst-auditmanymod1.so \
+ tst-auditmany-ENV = \
+ LD_AUDIT=tst-auditmanymod1.so:tst-auditmanymod2.so:tst-auditmanymod3.so:tst-auditmanymod4.so:tst-auditmanymod5.so:tst-auditmanymod6.so:tst-auditmanymod7.so:tst-auditmanymod8.so:tst-auditmanymod9.so
+
+-LDFLAGS-tst-audit14 = -Wl,--audit=tst-auditlogmod-1.so
++LDFLAGS-tst-audit14 = -Wl,--audit=tst-auditlogmod-1.so,--disable-new-dtags
+ $(objpfx)tst-auditlogmod-1.so: $(libsupport)
+ $(objpfx)tst-audit14.out: $(objpfx)tst-auditlogmod-1.so
++LDFLAGS-tst-audit14a = -Wl,--audit=tst-auditlogmod-1.so,--enable-new-dtags
++$(objpfx)tst-audit14a.out: $(objpfx)tst-auditlogmod-1.so
+ LDFLAGS-tst-audit15 = \
+ -Wl,--audit=tst-auditlogmod-1.so,--depaudit=tst-auditlogmod-2.so
+ $(objpfx)tst-auditlogmod-2.so: $(libsupport)
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index 1613217a236c7fc3..0b45e6e3db31c70d 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -2042,6 +2042,21 @@ _dl_map_object (struct link_map *loader, const char *name,
+ &main_map->l_rpath_dirs,
+ &realname, &fb, loader ?: main_map, LA_SER_RUNPATH,
+ &found_other_class);
++
++ /* Also try DT_RUNPATH in the executable for LD_AUDIT dlopen
++ call. */
++ if (__glibc_unlikely (mode & __RTLD_AUDIT)
++ && fd == -1 && !did_main_map
++ && main_map != NULL && main_map->l_type != lt_loaded)
++ {
++ struct r_search_path_struct l_rpath_dirs;
++ l_rpath_dirs.dirs = NULL;
++ if (cache_rpath (main_map, &l_rpath_dirs,
++ DT_RUNPATH, "RUNPATH"))
++ fd = open_path (name, namelen, mode, &l_rpath_dirs,
++ &realname, &fb, loader ?: main_map,
++ LA_SER_RUNPATH, &found_other_class);
++ }
+ }
+
+ /* Try the LD_LIBRARY_PATH environment variable. */
+diff --git a/elf/tst-audit14a.c b/elf/tst-audit14a.c
+new file mode 100644
+index 0000000000000000..c6232eacf2946e4e
+--- /dev/null
++++ b/elf/tst-audit14a.c
+@@ -0,0 +1 @@
++#include "tst-audit14.c"
diff --git a/glibc-rh2047981-29.patch b/glibc-rh2047981-29.patch
new file mode 100644
index 0000000000000000000000000000000000000000..3581baae6840ef361a424672dc2356af2060d8a1
--- /dev/null
+++ b/glibc-rh2047981-29.patch
@@ -0,0 +1,42 @@
+commit f4f70c2895e3d325188a42c10eb7bb4335be6773
+Author: H.J. Lu
+Date: Tue Jan 4 06:58:34 2022 -0800
+
+ elf: Add a comment after trailing backslashes
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 4ec4e9a049156755..53faca4585220048 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -308,6 +308,7 @@ tests-cxx = \
+ tst-nodelete \
+ tst-unique3 \
+ tst-unique4 \
++# tests-cxx
+
+ tests += $(if $(CXX),$(tests-cxx))
+ tests-internal += loadtest unload unload2 circleload1 \
+@@ -580,6 +581,7 @@ modules-names = \
+ vismod1 \
+ vismod2 \
+ vismod3 \
++# modules-names
+
+ modules-names-cxx = \
+ tst-dlopen-nodelete-reloc-mod1 \
+@@ -605,6 +607,7 @@ modules-names-cxx = \
+ tst-unique3lib \
+ tst-unique3lib2 \
+ tst-unique4lib \
++# modules-names-cxx
+
+ modules-names += \
+ $(if $(CXX),$(modules-names-cxx)) \
+@@ -614,6 +617,7 @@ modules-names += \
+ $(tst-tls-many-dynamic-modules-dep-bad) \
+ $(tlsmod17a-modules) \
+ $(tlsmod18a-modules) \
++# modules-names
+
+ # Most modules build with _ISOMAC defined, but those filtered out
+ # depend on internal headers.
diff --git a/glibc-rh2047981-3.patch b/glibc-rh2047981-3.patch
new file mode 100644
index 0000000000000000000000000000000000000000..aa0aaafb94e0ed4d13c0316edf7b41913c1872bf
--- /dev/null
+++ b/glibc-rh2047981-3.patch
@@ -0,0 +1,245 @@
+commit 8dbb7a08ec52057819db4ee234f9429ab99eb4ae
+Author: Vineet Gupta
+Date: Wed May 27 12:54:21 2020 -0700
+
+ dl-runtime: reloc_{offset,index} now functions arch overide'able
+
+ The existing macros are fragile and expect local variables with a
+ certain name. Fix this by defining them as functions with default
+ implementation in a new header dl-runtime.h which arches can override
+ if need be.
+
+ This came up during ARC port review, hence the need for argument pltgot
+ in reloc_index() which is not needed by existing ports.
+
+ This patch potentially only affects hppa/x86 ports,
+ build tested for both those configs and a few more.
+
+ Reviewed-by: Adhemerval Zanella
+
+diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
+index 72b03e000dcf190e..4ccd7c30678fafad 100644
+--- a/elf/dl-runtime.c
++++ b/elf/dl-runtime.c
+@@ -27,6 +27,7 @@
+ #include "dynamic-link.h"
+ #include
+ #include
++#include
+
+
+ #if (!ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
+@@ -42,13 +43,6 @@
+ # define ARCH_FIXUP_ATTRIBUTE
+ #endif
+
+-#ifndef reloc_offset
+-# define reloc_offset reloc_arg
+-# define reloc_index reloc_arg / sizeof (PLTREL)
+-#endif
+-
+-
+-
+ /* This function is called through a special trampoline from the PLT the
+ first time each PLT entry is called. We must perform the relocation
+ specified in the PLT of the given shared object, and return the resolved
+@@ -68,8 +62,11 @@ _dl_fixup (
+ = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
+
++ const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]);
++
+ const PLTREL *const reloc
+- = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
++ = (const void *) (D_PTR (l, l_info[DT_JMPREL])
++ + reloc_offset (pltgot, reloc_arg));
+ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
+ const ElfW(Sym) *refsym = sym;
+ void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
+@@ -180,9 +177,12 @@ _dl_profile_fixup (
+ l, reloc_arg);
+ }
+
++ const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]);
++
+ /* This is the address in the array where we store the result of previous
+ relocations. */
+- struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index];
++ struct reloc_result *reloc_result
++ = &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))];
+
+ /* CONCURRENCY NOTES:
+
+@@ -219,8 +219,11 @@ _dl_profile_fixup (
+ = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
+ const char *strtab = (const char *) D_PTR (l, l_info[DT_STRTAB]);
+
++ const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]);
++
+ const PLTREL *const reloc
+- = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
++ = (const void *) (D_PTR (l, l_info[DT_JMPREL])
++ + reloc_offset (pltgot, reloc_arg));
+ const ElfW(Sym) *refsym = &symtab[ELFW(R_SYM) (reloc->r_info)];
+ const ElfW(Sym) *defsym = refsym;
+ lookup_t result;
+@@ -485,11 +488,14 @@ _dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_arg,
+ const void *inregs, void *outregs)
+ {
+ #ifdef SHARED
++ const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]);
++
+ /* This is the address in the array where we store the result of previous
+ relocations. */
+ // XXX Maybe the bound information must be stored on the stack since
+ // XXX with bind_not a new value could have been stored in the meantime.
+- struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index];
++ struct reloc_result *reloc_result =
++ &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))];
+ ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
+ l_info[DT_SYMTAB])
+ + reloc_result->boundndx);
+diff --git a/elf/dl-runtime.h b/elf/dl-runtime.h
+new file mode 100644
+index 0000000000000000..78f1da77fb4ed905
+--- /dev/null
++++ b/elf/dl-runtime.h
+@@ -0,0 +1,30 @@
++/* Helpers for On-demand PLT fixup for shared objects. Generic version.
++ Copyright (C) 2020 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++static inline uintptr_t
++reloc_offset (uintptr_t plt0, uintptr_t pltn)
++{
++ return pltn;
++}
++
++static inline uintptr_t
++reloc_index (uintptr_t plt0, uintptr_t pltn, size_t size)
++{
++ return pltn / size;
++}
+diff --git a/sysdeps/hppa/dl-runtime.c b/sysdeps/hppa/dl-runtime.c
+index 885a3f1837cbc56d..2d061b150f0602c1 100644
+--- a/sysdeps/hppa/dl-runtime.c
++++ b/sysdeps/hppa/dl-runtime.c
+@@ -17,10 +17,6 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-/* Clear PA_GP_RELOC bit in relocation offset. */
+-#define reloc_offset (reloc_arg & ~PA_GP_RELOC)
+-#define reloc_index (reloc_arg & ~PA_GP_RELOC) / sizeof (PLTREL)
+-
+ #include
+
+ /* The caller has encountered a partially relocated function descriptor.
+diff --git a/sysdeps/hppa/dl-runtime.h b/sysdeps/hppa/dl-runtime.h
+new file mode 100644
+index 0000000000000000..6983aa0ae9b4296c
+--- /dev/null
++++ b/sysdeps/hppa/dl-runtime.h
+@@ -0,0 +1,31 @@
++/* Helpers for On-demand PLT fixup for shared objects. HPAA version.
++ Copyright (C) 2020 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* Clear PA_GP_RELOC bit in relocation offset. */
++static inline uintptr_t
++reloc_offset (uintptr_t plt0, uintptr_t pltn)
++{
++ return pltn & ~PA_GP_RELOC;
++}
++
++static inline uintptr_t
++reloc_index (uintptr_t plt0, uintptr_t pltn, size_t size)
++{
++ return (pltn & ~PA_GP_RELOC )/ size;
++}
+diff --git a/sysdeps/x86_64/dl-runtime.c b/sysdeps/x86_64/dl-runtime.c
+deleted file mode 100644
+index b625d1e88257b018..0000000000000000
+--- a/sysdeps/x86_64/dl-runtime.c
++++ /dev/null
+@@ -1,9 +0,0 @@
+-/* The ABI calls for the PLT stubs to pass the index of the relocation
+- and not its offset. In _dl_profile_fixup and _dl_call_pltexit we
+- also use the index. Therefore it is wasteful to compute the offset
+- in the trampoline just to reverse the operation immediately
+- afterwards. */
+-#define reloc_offset reloc_arg * sizeof (PLTREL)
+-#define reloc_index reloc_arg
+-
+-#include
+diff --git a/sysdeps/x86_64/dl-runtime.h b/sysdeps/x86_64/dl-runtime.h
+new file mode 100644
+index 0000000000000000..3fa61d7a4697cf3f
+--- /dev/null
++++ b/sysdeps/x86_64/dl-runtime.h
+@@ -0,0 +1,35 @@
++/* Helpers for On-demand PLT fixup for shared objects. x86_64 version.
++ Copyright (C) 2020 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* The ABI calls for the PLT stubs to pass the index of the relocation
++ and not its offset. In _dl_profile_fixup and _dl_call_pltexit we
++ also use the index. Therefore it is wasteful to compute the offset
++ in the trampoline just to reverse the operation immediately
++ afterwards. */
++static inline uintptr_t
++reloc_offset (uintptr_t plt0, uintptr_t pltn)
++{
++ return pltn * sizeof (ElfW(Rela));
++}
++
++static inline uintptr_t
++reloc_index (uintptr_t plt0, uintptr_t pltn, size_t size)
++{
++ return pltn;
++}
diff --git a/glibc-rh2047981-30.patch b/glibc-rh2047981-30.patch
new file mode 100644
index 0000000000000000000000000000000000000000..d52225fefc562851cd6a55c12fc3619f71f403e7
--- /dev/null
+++ b/glibc-rh2047981-30.patch
@@ -0,0 +1,520 @@
+commit 7de01e60c200c431d3469deb784da8fd4508fc15
+Author: Florian Weimer
+Date: Fri Jan 14 20:16:05 2022 +0100
+
+ elf/Makefile: Reflow and sort most variable assignments
+
+ Reviewed-by: H.J. Lu
+
+Conflicts:
+ elf/Makefile
+ Complete rewrite of reflow.
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 53faca4585220048..954cd08c199f5037 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -21,20 +21,60 @@ subdir := elf
+
+ include ../Makeconfig
+
+-headers = elf.h bits/elfclass.h link.h bits/link.h bits/link_lavcurrent.h
+-routines = $(all-dl-routines) dl-support dl-iteratephdr \
+- dl-addr dl-addr-obj enbl-secure dl-profstub \
+- dl-origin dl-libc dl-sym dl-sysdep dl-error \
+- dl-reloc-static-pie libc_early_init
++headers = \
++ bits/elfclass.h \
++ bits/link.h \
++ bits/link_lavcurrent.h \
++ elf.h \
++ link.h \
++ # headers
++
++routines = \
++ $(all-dl-routines) \
++ dl-addr \
++ dl-addr-obj \
++ dl-error \
++ dl-iteratephdr \
++ dl-libc \
++ dl-origin \
++ dl-profstub \
++ dl-reloc-static-pie \
++ dl-support \
++ dl-sym \
++ dl-sysdep \
++ enbl-secure \
++ libc_early_init \
++ # routines
+
+ # The core dynamic linking functions are in libc for the static and
+ # profiled libraries.
+-dl-routines = $(addprefix dl-,load lookup object reloc deps \
+- runtime init fini debug misc \
+- version profile tls origin scope \
+- execstack open close trampoline \
+- exception sort-maps lookup-direct \
+- call-libc-early-init write)
++dl-routines = \
++ dl-call-libc-early-init \
++ dl-close \
++ dl-debug \
++ dl-deps \
++ dl-exception \
++ dl-execstack \
++ dl-fini \
++ dl-init \
++ dl-load \
++ dl-lookup \
++ dl-lookup-direct \
++ dl-misc \
++ dl-object \
++ dl-open \
++ dl-origin \
++ dl-profile \
++ dl-reloc \
++ dl-runtime \
++ dl-scope \
++ dl-sort-maps \
++ dl-tls \
++ dl-trampoline \
++ dl-version \
++ dl-write \
++ # dl-routines
++
+ ifeq (yes,$(use-ldconfig))
+ dl-routines += dl-cache
+ endif
+@@ -57,15 +97,36 @@ endif
+
+ all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
+ # But they are absent from the shared libc, because that code is in ld.so.
+-elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \
+- dl-sysdep dl-exception dl-reloc-static-pie
++elide-routines.os = \
++ $(all-dl-routines) \
++ dl-exception \
++ dl-origin \
++ dl-reloc-static-pie \
++ dl-support \
++ dl-sysdep \
++ enbl-secure \
++ # elide-routines.os
+
+ # ld.so uses those routines, plus some special stuff for being the program
+ # interpreter and operating independent of libc.
+-rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \
+- dl-error-minimal dl-conflict dl-hwcaps dl-hwcaps_split dl-hwcaps-subdirs \
+- dl-usage dl-diagnostics dl-diagnostics-kernel dl-diagnostics-cpu \
+- dl-audit
++rtld-routines = \
++ $(all-dl-routines) \
++ dl-audit \
++ dl-conflict \
++ dl-diagnostics \
++ dl-diagnostics-cpu \
++ dl-diagnostics-kernel \
++ dl-environ \
++ dl-error-minimal \
++ dl-hwcaps \
++ dl-hwcaps-subdirs \
++ dl-hwcaps_split \
++ dl-minimal \
++ dl-sysdep \
++ dl-usage \
++ rtld \
++ # rtld-routines
++
+ all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines)
+
+ CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables
+@@ -98,8 +159,18 @@ ld-map = $(common-objpfx)ld.map
+ endif
+
+ ifeq (yes,$(build-shared))
+-extra-objs = $(all-rtld-routines:%=%.os) soinit.os sofini.os interp.os
+-generated += librtld.os dl-allobjs.os ld.so ldd
++extra-objs = \
++ $(all-rtld-routines:%=%.os) \
++ sofini.os \
++ soinit.os \
++ interp.os \
++ # extra-objs
++generated += \
++ dl-allobjs.os \
++ ldd \
++ ld.so \
++ librtld.os \
++ # generated
+ install-others = $(inst_rtlddir)/$(rtld-installed-name) $(inst_bindir)/ld.so
+ install-bin-script = ldd
+ endif
+@@ -117,8 +188,15 @@ others-static += ldconfig
+ others += ldconfig
+ install-rootsbin += ldconfig
+
+-ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs \
+- stringtable
++ldconfig-modules := \
++ cache \
++ chroot_canon \
++ readlib \
++ static-stubs \
++ stringtable \
++ xmalloc \
++ xstrdup \
++ # ldconfig-modules
+ extra-objs += $(ldconfig-modules:=.o)
+ others-extras = $(ldconfig-modules)
+ endif
+@@ -153,20 +231,34 @@ $(inst_auditdir)/sotruss-lib.so: $(objpfx)sotruss-lib.so $(+force)
+ $(do-install-program)
+ endif
+
+-tests-static-normal := tst-leaks1-static tst-array1-static tst-array5-static \
+- tst-dl-iter-static \
+- tst-tlsalign-static tst-tlsalign-extern-static \
+- tst-linkall-static tst-env-setuid tst-env-setuid-tunables \
+- tst-dst-static
+-tests-static-internal := tst-tls1-static tst-tls2-static \
+- tst-ptrguard1-static tst-stackguard1-static \
+- tst-tls1-static-non-pie tst-libc_dlvsym-static
++tests-static-normal := \
++ tst-array1-static \
++ tst-array5-static \
++ tst-dl-iter-static \
++ tst-dst-static \
++ tst-env-setuid \
++ tst-env-setuid-tunables \
++ tst-leaks1-static \
++ tst-linkall-static \
++ tst-tlsalign-extern-static \
++ tst-tlsalign-static \
++ # tests-static-normal
++
++tests-static-internal := \
++ tst-libc_dlvsym-static \
++ tst-ptrguard1-static \
++ tst-stackguard1-static \
++ tst-tls1-static \
++ tst-tls1-static-non-pie \
++ tst-tls2-static \
++ # tests-static-internal
+
+ CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o
+ tst-tls1-static-non-pie-no-pie = yes
+
+ tests-container = \
+- tst-ldconfig-bad-aux-cache
++ tst-ldconfig-bad-aux-cache \
++ # tests-container
+
+ ifeq (no,$(build-hardcoded-path-in-tests))
+ # This is an ld.so.cache test, and RPATH/RUNPATH in the executable
+@@ -174,14 +266,31 @@ ifeq (no,$(build-hardcoded-path-in-tests))
+ tests-container += tst-glibc-hwcaps-prepend-cache
+ endif
+
+-tests := tst-tls9 tst-leaks1 \
+- tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \
+- tst-auxv tst-stringtable
+-tests-internal := tst-tls1 tst-tls2 $(tests-static-internal)
++tests := \
++ tst-array1 \
++ tst-array2 \
++ tst-array3 \
++ tst-array4 \
++ tst-array5 \
++ tst-auxv \
++ tst-leaks1 \
++ tst-stringtable \
++ tst-tls9 \
++ # tests
++
++tests-internal := \
++ $(tests-static-internal) \
++ tst-tls1 \
++ tst-tls2 \
++ # tests-internal
++
+ tests-static := $(tests-static-normal) $(tests-static-internal)
+
+ ifeq (yes,$(build-shared))
+-tests-static += tst-tls9-static
++tests-static += \
++ tst-tls9-static \
++ # tests-static
++
+ tst-tls9-static-ENV = \
+ LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn
+
+@@ -302,37 +411,71 @@ tests += \
+ unload6 \
+ unload7 \
+ unload8 \
+-# reldep9
++ # tests
+ tests-cxx = \
+ tst-dlopen-nodelete-reloc \
+ tst-nodelete \
+ tst-unique3 \
+ tst-unique4 \
+-# tests-cxx
++ # tests-cxx
+
+ tests += $(if $(CXX),$(tests-cxx))
+-tests-internal += loadtest unload unload2 circleload1 \
+- neededtest neededtest2 neededtest3 neededtest4 \
+- tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
+- tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \
+- tst-create_format1 tst-tls-surplus tst-dl-hwcaps_split \
+- tst-audit19a
+-tests-container += tst-pldd tst-preload-pthread-libc
++
++tests-internal += \
++ circleload1 \
++ loadtest \
++ neededtest \
++ neededtest2 \
++ neededtest3 \
++ neededtest4 \
++ tst-audit19a \
++ tst-create_format1 \
++ tst-dl-hwcaps_split \
++ tst-dlmopen2 \
++ tst-libc_dlvsym \
++ tst-ptrguard1 \
++ tst-stackguard1 \
++ tst-tls-surplus \
++ tst-tls3 \
++ tst-tls6 \
++ tst-tls7 \
++ tst-tls8 \
++ unload \
++ unload2 \
++ # tests-internal
++
++tests-container += \
++ tst-pldd \
++ tst-preload-pthread-libc
++ # tests-container
++
+ ifeq ($(build-hardcoded-path-in-tests),yes)
+ tests += tst-dlopen-aout
+ tst-dlopen-aout-no-pie = yes
+ endif
+-test-srcs = tst-pathopt
++test-srcs = \
++ tst-pathopt
++ # tests-srcs
++
+ selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
++
+ ifneq ($(selinux-enabled),1)
+-tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
++tests-execstack-yes = \
++ tst-execstack \
++ tst-execstack-needed \
++ tst-execstack-prog \
++ # tests-execstack-yes
+ endif
+ endif
+ tests += $(tests-execstack-$(have-z-execstack))
+ ifeq ($(run-built-tests),yes)
+-tests-special += $(objpfx)tst-leaks1-mem.out \
+- $(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \
+- $(objpfx)tst-ldconfig-X.out $(objpfx)tst-rtld-help.out
++tests-special += \
++ $(objpfx)noload-mem.out \
++ $(objpfx)tst-ldconfig-X.out \
++ $(objpfx)tst-leaks1-mem.out \
++ $(objpfx)tst-leaks1-static-mem.out \
++ $(objpfx)tst-rtld-help.out \
++ # tests-special
+ endif
+ tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ tlsmod18a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+@@ -349,9 +492,16 @@ tst-tls-many-dynamic-modules-dep = \
+ tst-tls-many-dynamic-modules-dep-bad-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
+ tst-tls-many-dynamic-modules-dep-bad = \
+ $(foreach n,$(tst-tls-many-dynamic-modules-dep-bad-suffixes),tst-tls-manydynamic$(n)mod-dep-bad)
+-extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os) \
+- tst-tlsalign-vars.o
+-test-extras += tst-tlsmod17a tst-tlsmod18a tst-tlsalign-vars
++extra-test-objs += \
++ $(tlsmod17a-modules:=.os) \
++ $(tlsmod18a-modules:=.os) \
++ tst-tlsalign-vars.o \
++ # extra-test-objs
++test-extras += \
++ tst-tlsalign-vars \
++ tst-tlsmod17a \
++ tst-tlsmod18a \
++ # test-extras
+ modules-names = \
+ circlemod1 \
+ circlemod1a \
+@@ -607,17 +757,17 @@ modules-names-cxx = \
+ tst-unique3lib \
+ tst-unique3lib2 \
+ tst-unique4lib \
+-# modules-names-cxx
++ # modules-names-cxx
+
+ modules-names += \
+ $(if $(CXX),$(modules-names-cxx)) \
+ $(modules-execstack-$(have-z-execstack)) \
++ $(tlsmod17a-modules) \
++ $(tlsmod18a-modules) \
+ $(tst-tls-many-dynamic-modules) \
+ $(tst-tls-many-dynamic-modules-dep) \
+ $(tst-tls-many-dynamic-modules-dep-bad) \
+- $(tlsmod17a-modules) \
+- $(tlsmod18a-modules) \
+-# modules-names
++ # modules-names
+
+ # Most modules build with _ISOMAC defined, but those filtered out
+ # depend on internal headers.
+@@ -680,54 +830,103 @@ modules-names-nobuild := filtmod1
+ tests += $(tests-static)
+
+ ifneq (no,$(multi-arch))
+-tests-ifuncstatic := ifuncmain1static ifuncmain1picstatic \
+- ifuncmain2static ifuncmain2picstatic \
+- ifuncmain4static ifuncmain4picstatic \
+- ifuncmain5static ifuncmain5picstatic \
+- ifuncmain7static ifuncmain7picstatic
++tests-ifuncstatic := \
++ ifuncmain1static \
++ ifuncmain1picstatic \
++ ifuncmain2static \
++ ifuncmain2picstatic \
++ ifuncmain4static \
++ ifuncmain4picstatic \
++ ifuncmain5static \
++ ifuncmain5picstatic \
++ ifuncmain7static \
++ ifuncmain7picstatic \
++ # tests-ifuncstatic
+ tests-static += $(tests-ifuncstatic)
+ tests-internal += $(tests-ifuncstatic)
+ ifeq (yes,$(build-shared))
+ tests-internal += \
+- ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
+- ifuncmain1staticpic \
+- ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4 \
+- ifuncmain5 ifuncmain5pic ifuncmain5staticpic \
+- ifuncmain7 ifuncmain7pic
+-ifunc-test-modules = ifuncdep1 ifuncdep1pic ifuncdep2 ifuncdep2pic \
+- ifuncdep5 ifuncdep5pic
++ ifuncmain1 \
++ ifuncmain1pic \
++ ifuncmain1staticpic \
++ ifuncmain1vis \
++ ifuncmain1vispic \
++ ifuncmain2 \
++ ifuncmain2pic \
++ ifuncmain3 \
++ ifuncmain4 \
++ ifuncmain5 \
++ ifuncmain5pic \
++ ifuncmain5staticpic \
++ ifuncmain7 \
++ ifuncmain7pic \
++ # tests-internal
++ifunc-test-modules = \
++ ifuncdep1 \
++ ifuncdep1pic \
++ ifuncdep2 \
++ ifuncdep2pic \
++ ifuncdep5 \
++ ifuncdep5pic \
++ # ifunc-test-modules
+ extra-test-objs += $(ifunc-test-modules:=.o)
+ test-internal-extras += $(ifunc-test-modules)
+ ifeq (yes,$(have-fpie))
+-ifunc-pie-tests = ifuncmain1pie ifuncmain1vispie ifuncmain1staticpie \
+- ifuncmain5pie ifuncmain6pie ifuncmain7pie
++ifunc-pie-tests = \
++ ifuncmain1pie \
++ ifuncmain1staticpie \
++ ifuncmain1vispie \
++ ifuncmain5pie \
++ ifuncmain6pie \
++ ifuncmain7pie \
++ # ifunc-pie-tests
+ tests-internal += $(ifunc-pie-tests)
+ tests-pie += $(ifunc-pie-tests)
+ endif
+-modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6
++modules-names += \
++ ifuncmod1 \
++ ifuncmod3 \
++ ifuncmod5 \
++ ifuncmod6 \
++ # modules-names
+ endif
+ endif
+
+ ifeq (yes,$(build-shared))
+ ifeq ($(run-built-tests),yes)
+-tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \
+- $(objpfx)tst-rtld-preload.out $(objpfx)argv0test.out \
+- $(objpfx)tst-rtld-help.out
++tests-special += \
++ $(objpfx)argv0test.out \
++ $(objpfx)tst-pathopt.out \
++ $(objpfx)tst-rtld-help.out \
++ $(objpfx)tst-rtld-load-self.out \
++ $(objpfx)tst-rtld-preload.out \
++ # tests-special
+ endif
+-tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \
+- $(objpfx)check-wx-segment.out \
+- $(objpfx)check-localplt.out $(objpfx)check-initfini.out
++tests-special += \
++ $(objpfx)check-execstack.out \
++ $(objpfx)check-initfini.out \
++ $(objpfx)check-localplt.out \
++ $(objpfx)check-textrel.out \
++ $(objpfx)check-wx-segment.out \
++ # tests-special
+ endif
+
+ ifeq ($(run-built-tests),yes)
+-tests-special += $(objpfx)order-cmp.out $(objpfx)tst-array1-cmp.out \
+- $(objpfx)tst-array1-static-cmp.out \
+- $(objpfx)tst-array2-cmp.out $(objpfx)tst-array3-cmp.out \
+- $(objpfx)tst-array4-cmp.out $(objpfx)tst-array5-cmp.out \
+- $(objpfx)tst-array5-static-cmp.out $(objpfx)order2-cmp.out \
+- $(objpfx)tst-initorder-cmp.out \
+- $(objpfx)tst-initorder2-cmp.out $(objpfx)tst-unused-dep.out \
+- $(objpfx)tst-unused-dep-cmp.out
++tests-special += \
++ $(objpfx)order-cmp.out \
++ $(objpfx)order2-cmp.out \
++ $(objpfx)tst-array1-cmp.out \
++ $(objpfx)tst-array1-static-cmp.out \
++ $(objpfx)tst-array2-cmp.out \
++ $(objpfx)tst-array3-cmp.out \
++ $(objpfx)tst-array4-cmp.out \
++ $(objpfx)tst-array5-cmp.out \
++ $(objpfx)tst-array5-static-cmp.out \
++ $(objpfx)tst-initorder-cmp.out \
++ $(objpfx)tst-initorder2-cmp.out \
++ $(objpfx)tst-unused-dep-cmp.out \
++ $(objpfx)tst-unused-dep.out \
++ # tests-special
+ endif
+
+ check-abi: $(objpfx)check-abi-ld.out
+@@ -807,6 +1006,7 @@ rtld-stubbed-symbols = \
+ free \
+ malloc \
+ realloc \
++ # rtld-stubbed-symbols
+
+ # The GCC arguments that implement $(rtld-stubbed-symbols).
+ rtld-stubbed-symbols-args = \
diff --git a/glibc-rh2047981-31.patch b/glibc-rh2047981-31.patch
new file mode 100644
index 0000000000000000000000000000000000000000..48de026f8f19a13a04a0336b74a8dd1452ab9731
--- /dev/null
+++ b/glibc-rh2047981-31.patch
@@ -0,0 +1,440 @@
+Added $(objpfx)tst-audit23: $(libdl) to elf/Makefile since
+we still need $(libdl) in RHEL8.
+
+commit 5fa11a2bc94c912c3b25860065086902674537ba
+Author: Adhemerval Zanella
+Date: Mon Jan 24 10:46:15 2022 -0300
+
+ elf: Add la_activity during application exit
+
+ la_activity is not called during application exit, even though
+ la_objclose is.
+
+ Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
+
+ Reviewed-by: Carlos O'Donell
+ Tested-by: Carlos O'Donell
+
+Conflicts:
+ elf/Makefile
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 954cd08c199f5037..e4955c9f575f9015 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -345,6 +345,7 @@ tests += \
+ tst-audit2 \
+ tst-audit20 \
+ tst-audit22 \
++ tst-audit23 \
+ tst-audit8 \
+ tst-audit9 \
+ tst-auditmany \
+@@ -608,6 +609,7 @@ modules-names = \
+ tst-audit13mod1 \
+ tst-audit18mod \
+ tst-audit19bmod \
++ tst-audit23mod \
+ tst-auditlogmod-1 \
+ tst-auditlogmod-2 \
+ tst-auditlogmod-3 \
+@@ -630,6 +632,7 @@ modules-names = \
+ tst-auditmod19b \
+ tst-auditmod20 \
+ tst-auditmod22 \
++ tst-auditmod23 \
+ tst-big-note-lib \
+ tst-deep1mod1 \
+ tst-deep1mod2 \
+@@ -2041,6 +2044,11 @@ $(objpfx)tst-auditmod20.so: $(libdl)
+ $(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so
+ tst-audit22-ARGS = -- $(host-test-program-cmd)
+
++$(objpfx)tst-audit23: $(libdl)
++$(objpfx)tst-audit23.out: $(objpfx)tst-auditmod23.so \
++ $(objpfx)tst-audit23mod.so
++tst-audit23-ARGS = -- $(host-test-program-cmd)
++
+ # tst-sonamemove links against an older implementation of the library.
+ LDFLAGS-tst-sonamemove-linkmod1.so = \
+ -Wl,--version-script=tst-sonamemove-linkmod1.map \
+diff --git a/elf/dl-fini.c b/elf/dl-fini.c
+index e102d93647cb8c47..eea9d8aad736a99e 100644
+--- a/elf/dl-fini.c
++++ b/elf/dl-fini.c
+@@ -63,6 +63,10 @@ _dl_fini (void)
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ else
+ {
++#ifdef SHARED
++ _dl_audit_activity_nsid (ns, LA_ACT_DELETE);
++#endif
++
+ /* Now we can allocate an array to hold all the pointers and
+ copy the pointers in. */
+ struct link_map *maps[nloaded];
+@@ -153,6 +157,10 @@ _dl_fini (void)
+ /* Correct the previous increment. */
+ --l->l_direct_opencount;
+ }
++
++#ifdef SHARED
++ _dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT);
++#endif
+ }
+ }
+
+diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
+new file mode 100644
+index 0000000000000000..4904cf1340a97ee1
+--- /dev/null
++++ b/elf/tst-audit23.c
+@@ -0,0 +1,239 @@
++/* Check for expected la_objopen and la_objeclose for all objects.
++ 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
++ . */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include