diff --git a/SUPPORTED b/SUPPORTED index a4bf79c..fdf15fd 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 9183972..3cb3b47 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 0000000..9c0e36e --- /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 deleted file mode 100644 index 8fbe86d..0000000 --- a/glibc-Add-a-testcase-to-check-alignment-of-PT_LOAD-segment-2.patch +++ /dev/null @@ -1,148 +0,0 @@ -From ab887596903b159107e0be6f8b25986a5597cfca Mon Sep 17 00:00:00 2001 -From: "H.J. Lu" -Date: Mon, 7 Feb 2022 10:44:17 -0500 -Subject: [PATCH 2/4] Add a testcase to check alignment of PT_LOAD segment [BZ - #28676] - -Backport from master commit: fc2334a - -Signed-off-by: Rongwei Wang ---- - elf/Makefile | 14 ++++++++++++-- - elf/tst-align3.c | 38 ++++++++++++++++++++++++++++++++++++++ - elf/tst-alignmod3.c | 32 ++++++++++++++++++++++++++++++++ - 3 files changed, 82 insertions(+), 2 deletions(-) - create mode 100644 elf/tst-align3.c - create mode 100644 elf/tst-alignmod3.c - -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 -+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) - $(objpfx)tst-align: $(libdl) - $(objpfx)tst-align.out: $(objpfx)tst-alignmod.so - $(objpfx)tst-align2: $(objpfx)tst-alignmod2.so -+$(objpfx)tst-align3: $(objpfx)tst-alignmod3.so -+ifeq (yes,$(have-fpie)) -+CFLAGS-tst-align3.c += $(PIE-ccflag) -+endif -+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 -new file mode 100644 -index 00000000..ac86d623 ---- /dev/null -+++ b/elf/tst-align3.c -@@ -0,0 +1,38 @@ -+/* 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. -+ -+ 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 should cover all possible page sizes we currently support. */ -+#define ALIGN 0x200000 -+ -+int bar __attribute__ ((aligned (ALIGN))) = 1; -+ -+extern int do_load_test (void); -+ -+static int -+do_test (void) -+{ -+ printf ("bar: %p\n", &bar); -+ TEST_VERIFY (is_aligned (&bar, ALIGN) == 0); -+ -+ return do_load_test (); -+} -+ -+#include -diff --git a/elf/tst-alignmod3.c b/elf/tst-alignmod3.c -new file mode 100644 -index 00000000..0d33f237 ---- /dev/null -+++ b/elf/tst-alignmod3.c -@@ -0,0 +1,32 @@ -+/* 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. -+ -+ 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 should cover all possible page sizes we currently support. */ -+#define ALIGN 0x200000 -+ -+int foo __attribute__ ((aligned (ALIGN))) = 1; -+ -+void -+do_load_test (void) -+{ -+ printf ("foo: %p\n", &foo); -+ TEST_VERIFY (is_aligned (&foo, ALIGN) == 0); -+} --- -2.18.4 - diff --git a/glibc-LoongArch-Port.patch b/glibc-LoongArch-Port.patch deleted file mode 100644 index ca00cdd..0000000 --- a/glibc-LoongArch-Port.patch +++ /dev/null @@ -1,16504 +0,0 @@ -From b8f82ee8df870058d80a7a51bea14465235f06d5 Mon Sep 17 00:00:00 2001 -From: wanghongliang -Date: Thu, 23 Jun 2022 10:29:34 +0800 -Subject: [PATCH] glibc LoongArch Port. - -add LoongArch architecture support. - -Signed-off-by: wanghongliang ---- - README | 1 + - elf/elf.h | 84 + - scripts/config.sub | 7 +- - sysdeps/loongarch/Implies | 5 + - sysdeps/loongarch/Makefile | 32 + - sysdeps/loongarch/__longjmp.S | 50 + - sysdeps/loongarch/abort-instr.h | 2 + - sysdeps/loongarch/at_quick_exit.c | 1 + - sysdeps/loongarch/atexit.c | 1 + - sysdeps/loongarch/bits/endian.h | 9 + - sysdeps/loongarch/bits/fenv.h | 93 + - sysdeps/loongarch/bits/link.h | 56 + - sysdeps/loongarch/bits/setjmp.h | 39 + - sysdeps/loongarch/bits/wordsize.h | 22 + - sysdeps/loongarch/bsd-_setjmp.c | 1 + - sysdeps/loongarch/bsd-setjmp.c | 1 + - sysdeps/loongarch/configure | 4 + - sysdeps/loongarch/configure.ac | 6 + - sysdeps/loongarch/dl-irel.h | 51 + - sysdeps/loongarch/dl-machine.h | 366 +++ - sysdeps/loongarch/dl-tls.h | 49 + - sysdeps/loongarch/dl-trampoline.S | 108 + - sysdeps/loongarch/e_sqrtl.c | 39 + - sysdeps/loongarch/elf-init.c | 1 + - sysdeps/loongarch/fpu/e_sqrt.c | 29 + - sysdeps/loongarch/fpu/e_sqrtf.c | 28 + - sysdeps/loongarch/fpu/fclrexcpt.c | 47 + - sysdeps/loongarch/fpu/fedisblxcpt.c | 40 + - sysdeps/loongarch/fpu/feenablxcpt.c | 40 + - sysdeps/loongarch/fpu/fegetenv.c | 33 + - sysdeps/loongarch/fpu/fegetexcept.c | 33 + - sysdeps/loongarch/fpu/fegetmode.c | 27 + - sysdeps/loongarch/fpu/fegetround.c | 35 + - sysdeps/loongarch/fpu/feholdexcpt.c | 41 + - sysdeps/loongarch/fpu/fenv_libc.h | 31 + - sysdeps/loongarch/fpu/fesetenv.c | 44 + - sysdeps/loongarch/fpu/fesetexcept.c | 32 + - sysdeps/loongarch/fpu/fesetmode.c | 38 + - sysdeps/loongarch/fpu/fesetround.c | 46 + - sysdeps/loongarch/fpu/feupdateenv.c | 45 + - sysdeps/loongarch/fpu/fgetexcptflg.c | 39 + - sysdeps/loongarch/fpu/fraiseexcpt.c | 84 + - sysdeps/loongarch/fpu/fsetexcptflg.c | 42 + - sysdeps/loongarch/fpu/ftestexcept.c | 33 + - sysdeps/loongarch/fpu_control.h | 111 + - sysdeps/loongarch/fstat.c | 1 + - sysdeps/loongarch/fstat64.c | 1 + - sysdeps/loongarch/fstatat.c | 1 + - sysdeps/loongarch/fstatat64.c | 1 + - sysdeps/loongarch/gccframe.h | 21 + - sysdeps/loongarch/hp-timing.h | 40 + - sysdeps/loongarch/jmpbuf-offsets.h | 23 + - sysdeps/loongarch/jmpbuf-unwind.h | 46 + - sysdeps/loongarch/ldsodefs.h | 47 + - sysdeps/loongarch/libc-start.h | 25 + - sysdeps/loongarch/libc-tls.c | 32 + - sysdeps/loongarch/linkmap.h | 4 + - sysdeps/loongarch/lp64/Implies-after | 1 + - sysdeps/loongarch/lp64/libm-test-ulps | 2206 +++++++++++++++++ - sysdeps/loongarch/lp64/libm-test-ulps-name | 1 + - sysdeps/loongarch/lp64/memcpy.S | 402 +++ - sysdeps/loongarch/lp64/memmove.S | 476 ++++ - sysdeps/loongarch/lp64/memset.S | 175 ++ - sysdeps/loongarch/lp64/s_cosf.S | 409 +++ - sysdeps/loongarch/lp64/s_sinf.S | 392 +++ - sysdeps/loongarch/lp64/strchr.S | 140 ++ - sysdeps/loongarch/lp64/strchrnul.S | 156 ++ - sysdeps/loongarch/lp64/strcmp.S | 197 ++ - sysdeps/loongarch/lp64/strcpy.S | 210 ++ - sysdeps/loongarch/lp64/strlen.S | 135 + - sysdeps/loongarch/lp64/strncmp.S | 269 ++ - sysdeps/loongarch/lp64/strnlen.S | 155 ++ - sysdeps/loongarch/lstat.c | 1 + - sysdeps/loongarch/lstat64.c | 1 + - sysdeps/loongarch/machine-gmon.h | 37 + - sysdeps/loongarch/math_private.h | 245 ++ - sysdeps/loongarch/memusage.h | 21 + - sysdeps/loongarch/mknod.c | 1 + - sysdeps/loongarch/mknodat.c | 1 + - sysdeps/loongarch/nptl/Makefile | 26 + - .../loongarch/nptl/bits/pthreadtypes-arch.h | 68 + - sysdeps/loongarch/nptl/bits/semaphore.h | 33 + - sysdeps/loongarch/nptl/libc-lowlevellock.c | 8 + - sysdeps/loongarch/nptl/nptl-sysdep.S | 2 + - sysdeps/loongarch/nptl/pthread-offsets.h | 23 + - sysdeps/loongarch/nptl/pthreaddef.h | 32 + - sysdeps/loongarch/nptl/tcb-offsets.sym | 6 + - sysdeps/loongarch/nptl/tls.h | 147 ++ - sysdeps/loongarch/preconfigure | 9 + - sysdeps/loongarch/pthread_atfork.c | 1 + - sysdeps/loongarch/setjmp.S | 62 + - sysdeps/loongarch/sfp-machine.h | 79 + - sysdeps/loongarch/sotruss-lib.c | 51 + - sysdeps/loongarch/stack_chk_fail_local.c | 1 + - sysdeps/loongarch/stackinfo.h | 33 + - sysdeps/loongarch/start.S | 51 + - sysdeps/loongarch/stat.c | 1 + - sysdeps/loongarch/stat64.c | 1 + - sysdeps/loongarch/sys/asm.h | 49 + - sysdeps/loongarch/sys/regdef.h | 83 + - sysdeps/loongarch/tininess.h | 1 + - sysdeps/loongarch/tls-macros.h | 46 + - sysdeps/loongarch/tst-audit.h | 23 + - sysdeps/loongarch/warning-nop.c | 1 + - sysdeps/unix/sysv/linux/loongarch/Implies | 1 + - sysdeps/unix/sysv/linux/loongarch/Makefile | 17 + - sysdeps/unix/sysv/linux/loongarch/Versions | 44 + - .../sysv/linux/loongarch/atomic-machine.h | 188 ++ - .../unix/sysv/linux/loongarch/bits/fcntl.h | 62 + - .../sysv/linux/loongarch/bits/local_lim.h | 99 + - sysdeps/unix/sysv/linux/loongarch/bits/mman.h | 41 + - sysdeps/unix/sysv/linux/loongarch/bits/shm.h | 112 + - .../sysv/linux/loongarch/bits/sigcontext.h | 47 + - .../unix/sysv/linux/loongarch/bits/signum.h | 58 + - sysdeps/unix/sysv/linux/loongarch/clone.S | 98 + - sysdeps/unix/sysv/linux/loongarch/configure | 199 ++ - .../unix/sysv/linux/loongarch/configure.ac | 27 + - sysdeps/unix/sysv/linux/loongarch/dl-static.c | 84 + - .../unix/sysv/linux/loongarch/getcontext.S | 72 + - sysdeps/unix/sysv/linux/loongarch/getpid.c | 54 + - .../unix/sysv/linux/loongarch/gettimeofday.c | 58 + - sysdeps/unix/sysv/linux/loongarch/getuid.c | 60 + - .../unix/sysv/linux/loongarch/init-first.c | 57 + - sysdeps/unix/sysv/linux/loongarch/ipc_priv.h | 21 + - .../sysv/linux/loongarch/kernel-features.h | 24 + - .../unix/sysv/linux/loongarch/ldd-rewrite.sed | 1 + - sysdeps/unix/sysv/linux/loongarch/ldsodefs.h | 32 + - sysdeps/unix/sysv/linux/loongarch/libc-vdso.h | 37 + - .../unix/sysv/linux/loongarch/localplt.data | 13 + - .../unix/sysv/linux/loongarch/lp64/Implies | 3 + - .../sysv/linux/loongarch/lp64/c++-types.data | 67 + - .../linux/loongarch/lp64/jmp_buf-macros.h | 41 + - .../unix/sysv/linux/loongarch/lp64/ld.abilist | 5 + - .../loongarch/lp64/libBrokenLocale.abilist | 1 + - .../sysv/linux/loongarch/lp64/libanl.abilist | 4 + - .../sysv/linux/loongarch/lp64/libc.abilist | 2101 ++++++++++++++++ - .../linux/loongarch/lp64/libcrypt.abilist | 7 + - .../sysv/linux/loongarch/lp64/libdl.abilist | 9 + - .../sysv/linux/loongarch/lp64/libm.abilist | 1021 ++++++++ - .../sysv/linux/loongarch/lp64/libnsl.abilist | 120 + - .../linux/loongarch/lp64/libpthread.abilist | 264 ++ - .../linux/loongarch/lp64/libresolv.abilist | 79 + - .../sysv/linux/loongarch/lp64/librt.abilist | 35 + - .../linux/loongarch/lp64/libthread_db.abilist | 40 + - .../sysv/linux/loongarch/lp64/libutil.abilist | 6 + - .../unix/sysv/linux/loongarch/makecontext.c | 78 + - .../sysv/linux/loongarch/profil-counter.h | 31 + - sysdeps/unix/sysv/linux/loongarch/pt-vfork.S | 1 + - .../unix/sysv/linux/loongarch/register-dump.h | 63 + - .../unix/sysv/linux/loongarch/setcontext.S | 111 + - .../unix/sysv/linux/loongarch/shlib-versions | 2 + - .../sysv/linux/loongarch/sigcontextinfo.h | 22 + - .../unix/sysv/linux/loongarch/swapcontext.S | 120 + - .../unix/sysv/linux/loongarch/sys/procfs.h | 122 + - .../unix/sysv/linux/loongarch/sys/ucontext.h | 81 + - sysdeps/unix/sysv/linux/loongarch/sys/user.h | 31 + - sysdeps/unix/sysv/linux/loongarch/syscall.c | 36 + - sysdeps/unix/sysv/linux/loongarch/sysdep.S | 52 + - sysdeps/unix/sysv/linux/loongarch/sysdep.h | 333 +++ - .../sysv/linux/loongarch/ucontext-macros.h | 44 + - .../unix/sysv/linux/loongarch/ucontext_i.sym | 33 + - sysdeps/unix/sysv/linux/loongarch/vfork.S | 49 + - 162 files changed, 15153 insertions(+), 1 deletion(-) - create mode 100644 sysdeps/loongarch/Implies - create mode 100644 sysdeps/loongarch/Makefile - create mode 100644 sysdeps/loongarch/__longjmp.S - create mode 100644 sysdeps/loongarch/abort-instr.h - create mode 100644 sysdeps/loongarch/at_quick_exit.c - create mode 100644 sysdeps/loongarch/atexit.c - create mode 100644 sysdeps/loongarch/bits/endian.h - create mode 100644 sysdeps/loongarch/bits/fenv.h - create mode 100644 sysdeps/loongarch/bits/link.h - create mode 100644 sysdeps/loongarch/bits/setjmp.h - create mode 100644 sysdeps/loongarch/bits/wordsize.h - create mode 100644 sysdeps/loongarch/bsd-_setjmp.c - create mode 100644 sysdeps/loongarch/bsd-setjmp.c - create mode 100755 sysdeps/loongarch/configure - create mode 100644 sysdeps/loongarch/configure.ac - create mode 100644 sysdeps/loongarch/dl-irel.h - create mode 100644 sysdeps/loongarch/dl-machine.h - create mode 100644 sysdeps/loongarch/dl-tls.h - create mode 100644 sysdeps/loongarch/dl-trampoline.S - create mode 100644 sysdeps/loongarch/e_sqrtl.c - create mode 100644 sysdeps/loongarch/elf-init.c - create mode 100644 sysdeps/loongarch/fpu/e_sqrt.c - create mode 100644 sysdeps/loongarch/fpu/e_sqrtf.c - create mode 100644 sysdeps/loongarch/fpu/fclrexcpt.c - create mode 100644 sysdeps/loongarch/fpu/fedisblxcpt.c - create mode 100644 sysdeps/loongarch/fpu/feenablxcpt.c - create mode 100644 sysdeps/loongarch/fpu/fegetenv.c - create mode 100644 sysdeps/loongarch/fpu/fegetexcept.c - create mode 100644 sysdeps/loongarch/fpu/fegetmode.c - create mode 100644 sysdeps/loongarch/fpu/fegetround.c - create mode 100644 sysdeps/loongarch/fpu/feholdexcpt.c - create mode 100644 sysdeps/loongarch/fpu/fenv_libc.h - create mode 100644 sysdeps/loongarch/fpu/fesetenv.c - create mode 100644 sysdeps/loongarch/fpu/fesetexcept.c - create mode 100644 sysdeps/loongarch/fpu/fesetmode.c - create mode 100644 sysdeps/loongarch/fpu/fesetround.c - create mode 100644 sysdeps/loongarch/fpu/feupdateenv.c - create mode 100644 sysdeps/loongarch/fpu/fgetexcptflg.c - create mode 100644 sysdeps/loongarch/fpu/fraiseexcpt.c - create mode 100644 sysdeps/loongarch/fpu/fsetexcptflg.c - create mode 100644 sysdeps/loongarch/fpu/ftestexcept.c - create mode 100644 sysdeps/loongarch/fpu_control.h - create mode 100644 sysdeps/loongarch/fstat.c - create mode 100644 sysdeps/loongarch/fstat64.c - create mode 100644 sysdeps/loongarch/fstatat.c - create mode 100644 sysdeps/loongarch/fstatat64.c - create mode 100644 sysdeps/loongarch/gccframe.h - create mode 100644 sysdeps/loongarch/hp-timing.h - create mode 100644 sysdeps/loongarch/jmpbuf-offsets.h - create mode 100644 sysdeps/loongarch/jmpbuf-unwind.h - create mode 100644 sysdeps/loongarch/ldsodefs.h - create mode 100644 sysdeps/loongarch/libc-start.h - create mode 100644 sysdeps/loongarch/libc-tls.c - create mode 100644 sysdeps/loongarch/linkmap.h - create mode 100644 sysdeps/loongarch/lp64/Implies-after - create mode 100644 sysdeps/loongarch/lp64/libm-test-ulps - create mode 100644 sysdeps/loongarch/lp64/libm-test-ulps-name - create mode 100644 sysdeps/loongarch/lp64/memcpy.S - create mode 100644 sysdeps/loongarch/lp64/memmove.S - create mode 100644 sysdeps/loongarch/lp64/memset.S - create mode 100644 sysdeps/loongarch/lp64/s_cosf.S - create mode 100644 sysdeps/loongarch/lp64/s_sinf.S - create mode 100644 sysdeps/loongarch/lp64/strchr.S - create mode 100644 sysdeps/loongarch/lp64/strchrnul.S - create mode 100644 sysdeps/loongarch/lp64/strcmp.S - create mode 100644 sysdeps/loongarch/lp64/strcpy.S - create mode 100644 sysdeps/loongarch/lp64/strlen.S - create mode 100644 sysdeps/loongarch/lp64/strncmp.S - create mode 100644 sysdeps/loongarch/lp64/strnlen.S - create mode 100644 sysdeps/loongarch/lstat.c - create mode 100644 sysdeps/loongarch/lstat64.c - create mode 100644 sysdeps/loongarch/machine-gmon.h - create mode 100644 sysdeps/loongarch/math_private.h - create mode 100644 sysdeps/loongarch/memusage.h - create mode 100644 sysdeps/loongarch/mknod.c - create mode 100644 sysdeps/loongarch/mknodat.c - create mode 100644 sysdeps/loongarch/nptl/Makefile - create mode 100644 sysdeps/loongarch/nptl/bits/pthreadtypes-arch.h - create mode 100644 sysdeps/loongarch/nptl/bits/semaphore.h - create mode 100644 sysdeps/loongarch/nptl/libc-lowlevellock.c - create mode 100644 sysdeps/loongarch/nptl/nptl-sysdep.S - create mode 100644 sysdeps/loongarch/nptl/pthread-offsets.h - create mode 100644 sysdeps/loongarch/nptl/pthreaddef.h - create mode 100644 sysdeps/loongarch/nptl/tcb-offsets.sym - create mode 100644 sysdeps/loongarch/nptl/tls.h - create mode 100644 sysdeps/loongarch/preconfigure - create mode 100644 sysdeps/loongarch/pthread_atfork.c - create mode 100644 sysdeps/loongarch/setjmp.S - create mode 100644 sysdeps/loongarch/sfp-machine.h - create mode 100644 sysdeps/loongarch/sotruss-lib.c - create mode 100644 sysdeps/loongarch/stack_chk_fail_local.c - create mode 100644 sysdeps/loongarch/stackinfo.h - create mode 100644 sysdeps/loongarch/start.S - create mode 100644 sysdeps/loongarch/stat.c - create mode 100644 sysdeps/loongarch/stat64.c - create mode 100644 sysdeps/loongarch/sys/asm.h - create mode 100644 sysdeps/loongarch/sys/regdef.h - create mode 100644 sysdeps/loongarch/tininess.h - create mode 100644 sysdeps/loongarch/tls-macros.h - create mode 100644 sysdeps/loongarch/tst-audit.h - create mode 100644 sysdeps/loongarch/warning-nop.c - create mode 100644 sysdeps/unix/sysv/linux/loongarch/Implies - create mode 100644 sysdeps/unix/sysv/linux/loongarch/Makefile - create mode 100644 sysdeps/unix/sysv/linux/loongarch/Versions - create mode 100644 sysdeps/unix/sysv/linux/loongarch/atomic-machine.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/bits/fcntl.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/bits/local_lim.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/bits/mman.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/bits/shm.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/bits/sigcontext.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/bits/signum.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/clone.S - create mode 100644 sysdeps/unix/sysv/linux/loongarch/configure - create mode 100644 sysdeps/unix/sysv/linux/loongarch/configure.ac - create mode 100644 sysdeps/unix/sysv/linux/loongarch/dl-static.c - create mode 100644 sysdeps/unix/sysv/linux/loongarch/getcontext.S - create mode 100644 sysdeps/unix/sysv/linux/loongarch/getpid.c - create mode 100644 sysdeps/unix/sysv/linux/loongarch/gettimeofday.c - create mode 100644 sysdeps/unix/sysv/linux/loongarch/getuid.c - create mode 100644 sysdeps/unix/sysv/linux/loongarch/init-first.c - create mode 100644 sysdeps/unix/sysv/linux/loongarch/ipc_priv.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/kernel-features.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/ldd-rewrite.sed - create mode 100644 sysdeps/unix/sysv/linux/loongarch/ldsodefs.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/libc-vdso.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/localplt.data - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/Implies - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/c++-types.data - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/jmp_buf-macros.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/ld.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libBrokenLocale.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libanl.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libcrypt.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libdl.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libm.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libnsl.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libpthread.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libresolv.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/librt.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libthread_db.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/lp64/libutil.abilist - create mode 100644 sysdeps/unix/sysv/linux/loongarch/makecontext.c - create mode 100644 sysdeps/unix/sysv/linux/loongarch/profil-counter.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/pt-vfork.S - create mode 100644 sysdeps/unix/sysv/linux/loongarch/register-dump.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/setcontext.S - create mode 100644 sysdeps/unix/sysv/linux/loongarch/shlib-versions - create mode 100644 sysdeps/unix/sysv/linux/loongarch/sigcontextinfo.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/swapcontext.S - create mode 100644 sysdeps/unix/sysv/linux/loongarch/sys/procfs.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/sys/ucontext.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/sys/user.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/syscall.c - create mode 100644 sysdeps/unix/sysv/linux/loongarch/sysdep.S - create mode 100644 sysdeps/unix/sysv/linux/loongarch/sysdep.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/ucontext-macros.h - create mode 100644 sysdeps/unix/sysv/linux/loongarch/ucontext_i.sym - create mode 100644 sysdeps/unix/sysv/linux/loongarch/vfork.S - -diff --git a/README b/README -index 27a9fd47..1b5e147d 100644 ---- a/README -+++ b/README -@@ -41,6 +41,7 @@ The GNU C Library supports these configurations for using Linux kernels: - sh[34]-*-linux-gnu - sparc*-*-linux-gnu - sparc64*-*-linux-gnu -+ loongarch64-*-linux-gnu - - If you are interested in doing a port, please contact the glibc - maintainers; see http://www.gnu.org/software/libc/ for more -diff --git a/elf/elf.h b/elf/elf.h -index d6506ea1..0dc58b6d 100644 ---- a/elf/elf.h -+++ b/elf/elf.h -@@ -360,6 +360,7 @@ typedef struct - #define EM_RISCV 243 /* RISC-V */ - - #define EM_BPF 247 /* Linux BPF -- in-kernel virtual machine */ -+#define EM_LOONGARCH 258 /* Loongson Loongarch */ - - #define EM_NUM 248 - -@@ -3935,6 +3936,89 @@ enum - #define R_NDS32_TLS_TPOFF 102 - #define R_NDS32_TLS_DESC 119 - -+/* LoongISA ELF Flags */ -+#define EF_LARCH_ABI 0x0003 -+#define EF_LARCH_ABI_LP64 0x0003 -+#define EF_LARCH_ABI_LPX32 0x0002 -+#define EF_LARCH_ABI_LP32 0x0001 -+ -+/* Loongarch specific dynamic relocations. */ -+#define R_LARCH_NONE 0 -+#define R_LARCH_32 1 -+#define R_LARCH_64 2 -+#define R_LARCH_RELATIVE 3 -+#define R_LARCH_COPY 4 -+#define R_LARCH_JUMP_SLOT 5 -+#define R_LARCH_TLS_DTPMOD32 6 -+#define R_LARCH_TLS_DTPMOD64 7 -+#define R_LARCH_TLS_DTPREL32 8 -+#define R_LARCH_TLS_DTPREL64 9 -+#define R_LARCH_TLS_TPREL32 10 -+#define R_LARCH_TLS_TPREL64 11 -+#define R_LARCH_IRELATIVE 12 -+ -+/* Reserved for future relocs that the dynamic linker must understand. */ -+ -+/* used by the static linker for relocating .text */ -+#define R_LARCH_MARK_LA 20 -+#define R_LARCH_MARK_PCREL 21 -+ -+/* 这个重定位类型将symbol距离重定位位置的pc相对位置偏移量压栈。 -+ 它against symbol,因为如果是个常数,虽然在no-pic的情况下可以得到结果,但因为 -+ 重定位位置相对这个常数的偏移量一定很大,八成填不进去;而在pic的情况下, -+ 偏移量无法在静态连接时确定。因此我们约定这个重定位不可能against constant */ -+#define R_LARCH_SOP_PUSH_PCREL 22 -+ -+/* 这个重定位against a symbol or a constant。它将symbol的运行时绝对地址 -+ 或常数压栈,因此在pic的情况下会报错。另外我不太清楚常数和ABS段的关系。 */ -+#define R_LARCH_SOP_PUSH_ABSOLUTE 23 -+#define R_LARCH_SOP_PUSH_DUP 24 -+#define R_LARCH_SOP_PUSH_GPREL 25 -+#define R_LARCH_SOP_PUSH_TLS_TPREL 26 -+#define R_LARCH_SOP_PUSH_TLS_GOT 27 -+#define R_LARCH_SOP_PUSH_TLS_GD 28 -+#define R_LARCH_SOP_PUSH_PLT_PCREL 29 -+ -+#define R_LARCH_SOP_ASSERT 30 -+#define R_LARCH_SOP_NOT 31 -+#define R_LARCH_SOP_SUB 32 -+#define R_LARCH_SOP_SL 33 -+#define R_LARCH_SOP_SR 34 -+#define R_LARCH_SOP_ADD 35 -+#define R_LARCH_SOP_AND 36 -+#define R_LARCH_SOP_IF_ELSE 37 -+#define R_LARCH_SOP_POP_32_S_10_5 38 -+#define R_LARCH_SOP_POP_32_U_10_12 39 -+#define R_LARCH_SOP_POP_32_S_10_12 40 -+#define R_LARCH_SOP_POP_32_S_10_16 41 -+#define R_LARCH_SOP_POP_32_S_10_16_S2 42 -+#define R_LARCH_SOP_POP_32_S_5_20 43 -+#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44 -+#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45 -+#define R_LARCH_SOP_POP_32_U 46 -+ -+/* used by the static linker for relocating non .text */ -+/* 这几个重定位类型是为了照顾到 ".dword sym1 - sym2" 这种求差的写法。 -+ 这些重定位类型处理的是连接时地址,一般情况下它们是成对出现的。 -+ 在直接求负数".dword - sym1"的情况下,R_LARCH_SUBxx会单独出现。但注意, -+ 那个位置填进去的是连接时地址。 */ -+#define R_LARCH_ADD8 47 -+#define R_LARCH_ADD16 48 -+#define R_LARCH_ADD24 49 -+#define R_LARCH_ADD32 50 -+#define R_LARCH_ADD64 51 -+#define R_LARCH_SUB8 52 -+#define R_LARCH_SUB16 53 -+#define R_LARCH_SUB24 54 -+#define R_LARCH_SUB32 55 -+#define R_LARCH_SUB64 56 -+ -+ /* I don't know what it is. Existing in almost all other arch */ -+#define R_LARCH_GNU_VTINHERIT 57 -+#define R_LARCH_GNU_VTENTRY 58 -+ -+ -+ - __END_DECLS - - #endif /* elf.h */ -diff --git a/scripts/config.sub b/scripts/config.sub -index f2632cd8..34e9313f 100755 ---- a/scripts/config.sub -+++ b/scripts/config.sub -@@ -142,7 +142,7 @@ case $os in - -sun*os*) - # Prevent following clause from handling this invalid input. - ;; -- -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -+ -dec* | -mips* | -loongarch* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -@@ -288,6 +288,7 @@ case $basic_machine in - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ -+ | loongarch | loongarch64 \ - | mn10200 | mn10300 \ - | moxie \ - | mt \ -@@ -415,6 +416,7 @@ case $basic_machine in - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipsr5900-* | mipsr5900el-* \ - | mipstx39-* | mipstx39el-* \ -+ | loongarch-* | loongarch64-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ -@@ -1339,6 +1341,9 @@ case $basic_machine in - pmac | pmac-mpw) - basic_machine=powerpc-apple - ;; -+ loongarch) -+ basic_machine=loongarch-loongson -+ ;; - *-unknown) - # Make sure to match an already-canonicalized machine name. - ;; -diff --git a/sysdeps/loongarch/Implies b/sysdeps/loongarch/Implies -new file mode 100644 -index 00000000..c88325b8 ---- /dev/null -+++ b/sysdeps/loongarch/Implies -@@ -0,0 +1,5 @@ -+init_array -+ -+ieee754/ldbl-128 -+ieee754/dbl-64 -+ieee754/flt-32 -diff --git a/sysdeps/loongarch/Makefile b/sysdeps/loongarch/Makefile -new file mode 100644 -index 00000000..d5801b3c ---- /dev/null -+++ b/sysdeps/loongarch/Makefile -@@ -0,0 +1,32 @@ -+ifeq ($(subdir),misc) -+sysdep_headers += sys/asm.h -+endif -+ -+# LoongArch's assembler also needs to know about PIC as it changes the definition -+# of some assembler macros. -+ASFLAGS-.os += $(pic-ccflag) -+CFLAGS-elf-init.oS += -mcmodel=large -+CFLAGS-atexit.oS += -mcmodel=large -+CFLAGS-at_quick_exit.oS += -mcmodel=large -+CFLAGS-stat.oS += -mcmodel=large -+CFLAGS-fstat.oS += -mcmodel=large -+CFLAGS-lstat.oS += -mcmodel=large -+CFLAGS-stat64.oS += -mcmodel=large -+CFLAGS-fstat64.oS += -mcmodel=large -+CFLAGS-lstat64.oS += -mcmodel=large -+CFLAGS-fstatat.oS += -mcmodel=large -+CFLAGS-fstatat64.oS += -mcmodel=large -+CFLAGS-mknod.oS += -mcmodel=large -+CFLAGS-mknodat.oS += -mcmodel=large -+CFLAGS-pthread_atfork.oS += -mcmodel=large -+CFLAGS-warning-nop.oS += -mcmodel=large -+CFLAGS-stack_chk_fail_local.oS += -mcmodel=large -+ -+abi-variants := lp32 lp64 -+ -+ifeq (,$(filter $(default-abi),$(abi-variants))) -+$(error Unknown ABI $(default-abi), must be one of $(abi-variants)) -+endif -+ -+abi-lp64-condition := defined _ABILP64 -+abi-lp32-condition := defined _ABILP32 -diff --git a/sysdeps/loongarch/__longjmp.S b/sysdeps/loongarch/__longjmp.S -new file mode 100644 -index 00000000..68f67639 ---- /dev/null -+++ b/sysdeps/loongarch/__longjmp.S -@@ -0,0 +1,50 @@ -+/* Copyright (C) 2020-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 -+ -+ENTRY (__longjmp) -+ REG_L ra, a0, 0*SZREG -+ REG_L sp, a0, 1*SZREG -+ REG_L x, a0, 2*SZREG -+ REG_L fp, a0, 3*SZREG -+ REG_L s0, a0, 4*SZREG -+ REG_L s1, a0, 5*SZREG -+ REG_L s2, a0, 6*SZREG -+ REG_L s3, a0, 7*SZREG -+ REG_L s4, a0, 8*SZREG -+ REG_L s5, a0, 9*SZREG -+ REG_L s6, a0, 10*SZREG -+ REG_L s7, a0, 11*SZREG -+ REG_L s8, a0, 12*SZREG -+ -+ FREG_L $f24, a0, 13*SZREG + 0*SZFREG -+ FREG_L $f25, a0, 13*SZREG + 1*SZFREG -+ FREG_L $f26, a0, 13*SZREG + 2*SZFREG -+ FREG_L $f27, a0, 13*SZREG + 3*SZFREG -+ FREG_L $f28, a0, 13*SZREG + 4*SZFREG -+ FREG_L $f29, a0, 13*SZREG + 5*SZFREG -+ FREG_L $f30, a0, 13*SZREG + 6*SZFREG -+ FREG_L $f31, a0, 13*SZREG + 7*SZFREG -+ -+ sltui a0,a1,1 -+ add.d a0, a0, a1 # a0 = (a1 == 0) ? 1 : a1 -+ jirl zero,ra,0 -+ -+END (__longjmp) -diff --git a/sysdeps/loongarch/abort-instr.h b/sysdeps/loongarch/abort-instr.h -new file mode 100644 -index 00000000..46d3ad08 ---- /dev/null -+++ b/sysdeps/loongarch/abort-instr.h -@@ -0,0 +1,2 @@ -+/* An instruction which should crash any program is a breakpoint. */ -+#define ABORT_INSTRUCTION asm ("break 0") -diff --git a/sysdeps/loongarch/at_quick_exit.c b/sysdeps/loongarch/at_quick_exit.c -new file mode 100644 -index 00000000..8d4b44a7 ---- /dev/null -+++ b/sysdeps/loongarch/at_quick_exit.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/atexit.c b/sysdeps/loongarch/atexit.c -new file mode 100644 -index 00000000..fc055a48 ---- /dev/null -+++ b/sysdeps/loongarch/atexit.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/bits/endian.h b/sysdeps/loongarch/bits/endian.h -new file mode 100644 -index 00000000..dc9a3f2e ---- /dev/null -+++ b/sysdeps/loongarch/bits/endian.h -@@ -0,0 +1,9 @@ -+/* The MIPS architecture has selectable endianness. -+ It exists in both little and big endian flavours and we -+ want to be able to share the installed header files between -+ both, so we define __BYTE_ORDER based on GCC's predefines. */ -+ -+#ifndef _ENDIAN_H -+# error "Never use directly; include instead." -+#endif -+# define __BYTE_ORDER __LITTLE_ENDIAN -diff --git a/sysdeps/loongarch/bits/fenv.h b/sysdeps/loongarch/bits/fenv.h -new file mode 100644 -index 00000000..42767412 ---- /dev/null -+++ b/sysdeps/loongarch/bits/fenv.h -@@ -0,0 +1,93 @@ -+/* Copyright (C) 1998-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#ifndef _FENV_H -+# error "Never use directly; include instead." -+#endif -+ -+ -+/* Define bits representing the exception. We use the bit positions -+ of the appropriate bits in the FPU control word. */ -+enum -+ { -+ FE_INEXACT = -+#define FE_INEXACT 0x010000 -+ FE_INEXACT, -+ FE_UNDERFLOW = -+#define FE_UNDERFLOW 0x020000 -+ FE_UNDERFLOW, -+ FE_OVERFLOW = -+#define FE_OVERFLOW 0x040000 -+ FE_OVERFLOW, -+ FE_DIVBYZERO = -+#define FE_DIVBYZERO 0x080000 -+ FE_DIVBYZERO, -+ FE_INVALID = -+#define FE_INVALID 0x100000 -+ FE_INVALID, -+ }; -+ -+#define FE_ALL_EXCEPT \ -+ (FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID) -+ -+/* The MIPS FPU supports all of the four defined rounding modes. We -+ use again the bit positions in the FPU control word as the values -+ for the appropriate macros. */ -+enum -+ { -+ FE_TONEAREST = -+#define FE_TONEAREST 0x000 -+ FE_TONEAREST, -+ FE_TOWARDZERO = -+#define FE_TOWARDZERO 0x100 -+ FE_TOWARDZERO, -+ FE_UPWARD = -+#define FE_UPWARD 0x200 -+ FE_UPWARD, -+ FE_DOWNWARD = -+#define FE_DOWNWARD 0x300 -+ FE_DOWNWARD -+ }; -+ -+ -+/* Type representing exception flags. */ -+typedef unsigned int fexcept_t; -+ -+ -+/* Type representing floating-point environment. This function corresponds -+ to the layout of the block written by the `fstenv'. */ -+typedef struct -+ { -+ unsigned int __fp_control_register; -+ } -+fenv_t; -+ -+/* If the default argument is used we use this value. */ -+#define FE_DFL_ENV ((const fenv_t *) -1) -+ -+#ifdef __USE_GNU -+/* Floating-point environment where none of the exception is masked. */ -+# define FE_NOMASK_ENV ((const fenv_t *) -257) -+#endif -+ -+#if __GLIBC_USE (IEC_60559_BFP_EXT) -+/* Type representing floating-point control modes. */ -+typedef unsigned int femode_t; -+ -+/* Default floating-point control modes. */ -+# define FE_DFL_MODE ((const femode_t *) -1L) -+#endif -diff --git a/sysdeps/loongarch/bits/link.h b/sysdeps/loongarch/bits/link.h -new file mode 100644 -index 00000000..554dfdc0 ---- /dev/null -+++ b/sysdeps/loongarch/bits/link.h -@@ -0,0 +1,56 @@ -+/* Copyright (C) 2020-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 -+ -+typedef struct La_loongarch_regs -+{ -+ unsigned long int lr_reg[8]; /* a0 - a7 */ -+ double lr_fpreg[8]; /* fa0 - fa7 */ -+ unsigned long int lr_ra; -+ unsigned long int lr_sp; -+} La_loongarch_regs; -+ -+/* Return values for calls from PLT on LoongArch. */ -+typedef struct La_loongarch_retval -+{ -+ unsigned long int lrv_a0; -+ unsigned long int lrv_a1; -+ double lrv_fa0; -+ double lrv_fa1; -+} La_loongarch_retval; -+ -+__BEGIN_DECLS -+ -+extern ElfW(Addr) la_loongarch_gnu_pltenter (ElfW(Sym) *__sym, unsigned int __ndx, -+ uintptr_t *__refcook, -+ uintptr_t *__defcook, -+ La_loongarch_regs *__regs, -+ unsigned int *__flags, -+ const char *__symname, -+ long int *__framesizep); -+extern unsigned int la_loongarch_gnu_pltexit (ElfW(Sym) *__sym, unsigned int __ndx, -+ uintptr_t *__refcook, -+ uintptr_t *__defcook, -+ const La_loongarch_regs *__inregs, -+ La_loongarch_retval *__outregs, -+ const char *__symname); -+ -+__END_DECLS -diff --git a/sysdeps/loongarch/bits/setjmp.h b/sysdeps/loongarch/bits/setjmp.h -new file mode 100644 -index 00000000..cc9b6bfd ---- /dev/null -+++ b/sysdeps/loongarch/bits/setjmp.h -@@ -0,0 +1,39 @@ -+/* Copyright (C) 2020-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 _LOONGARCH_BITS_SETJMP_H -+#define _LOONGARCH_BITS_SETJMP_H -+ -+typedef struct __jmp_buf_internal_tag -+ { -+ /* Program counter. */ -+ long int __pc; -+ /* Stack pointer. */ -+ long int __sp; -+ /* Reserved */ -+ long int __x; -+ /* Frame pointer. */ -+ long int __fp; -+ /* Callee-saved registers. */ -+ long int __regs[9]; -+ -+ /* Callee-saved floating point registers. */ -+ double __fpregs[8]; -+ } __jmp_buf[1]; -+ -+#endif /* _LOONGARCH_BITS_SETJMP_H */ -diff --git a/sysdeps/loongarch/bits/wordsize.h b/sysdeps/loongarch/bits/wordsize.h -new file mode 100644 -index 00000000..8dbaa00d ---- /dev/null -+++ b/sysdeps/loongarch/bits/wordsize.h -@@ -0,0 +1,22 @@ -+/* Copyright (C) 1999-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#define __loongarch_xlen 64 -+ -+#define __WORDSIZE __loongarch_xlen -+#define __WORDSIZE_TIME64_COMPAT32 0 -+ -diff --git a/sysdeps/loongarch/bsd-_setjmp.c b/sysdeps/loongarch/bsd-_setjmp.c -new file mode 100644 -index 00000000..0d413101 ---- /dev/null -+++ b/sysdeps/loongarch/bsd-_setjmp.c -@@ -0,0 +1 @@ -+/* _setjmp is implemented in setjmp.S */ -diff --git a/sysdeps/loongarch/bsd-setjmp.c b/sysdeps/loongarch/bsd-setjmp.c -new file mode 100644 -index 00000000..ee7c5e34 ---- /dev/null -+++ b/sysdeps/loongarch/bsd-setjmp.c -@@ -0,0 +1 @@ -+/* setjmp is implemented in setjmp.S */ -diff --git a/sysdeps/loongarch/configure b/sysdeps/loongarch/configure -new file mode 100755 -index 00000000..1e5abf81 ---- /dev/null -+++ b/sysdeps/loongarch/configure -@@ -0,0 +1,4 @@ -+# This file is generated from configure.ac by Autoconf. DO NOT EDIT! -+ # Local configure fragment for sysdeps/loongarch/elf. -+ -+#AC_DEFINE(PI_STATIC_AND_HIDDEN) -diff --git a/sysdeps/loongarch/configure.ac b/sysdeps/loongarch/configure.ac -new file mode 100644 -index 00000000..67b46ce0 ---- /dev/null -+++ b/sysdeps/loongarch/configure.ac -@@ -0,0 +1,6 @@ -+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory. -+# Local configure fragment for sysdeps/loongarch/elf. -+ -+dnl It is always possible to access static and hidden symbols in an -+dnl position independent way. -+#AC_DEFINE(PI_STATIC_AND_HIDDEN) -diff --git a/sysdeps/loongarch/dl-irel.h b/sysdeps/loongarch/dl-irel.h -new file mode 100644 -index 00000000..4216fec2 ---- /dev/null -+++ b/sysdeps/loongarch/dl-irel.h -@@ -0,0 +1,51 @@ -+/* Machine-dependent ELF indirect relocation inline functions. -+ x86-64 version. -+ Copyright (C) 2009-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#ifndef _DL_IREL_H -+#define _DL_IREL_H -+ -+#include -+#include -+ -+#define ELF_MACHINE_IRELA 1 -+ -+static inline ElfW(Addr) -+__attribute ((always_inline)) -+elf_ifunc_invoke (ElfW(Addr) addr) -+{ -+ return ((ElfW(Addr) (*) (void)) (addr)) (); -+} -+ -+static inline void -+__attribute ((always_inline)) -+elf_irela (const ElfW(Rela) *reloc) -+{ -+ ElfW(Addr) *const reloc_addr = (void *) reloc->r_offset; -+ const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info); -+ -+ if (__glibc_likely (r_type == R_LARCH_IRELATIVE)) -+ { -+ ElfW(Addr) value = elf_ifunc_invoke(reloc->r_addend); -+ *reloc_addr = value; -+ } -+ else -+ __libc_fatal ("Unexpected reloc type in static binary.\n"); -+} -+ -+#endif /* dl-irel.h */ -diff --git a/sysdeps/loongarch/dl-machine.h b/sysdeps/loongarch/dl-machine.h -new file mode 100644 -index 00000000..2a5e3767 ---- /dev/null -+++ b/sysdeps/loongarch/dl-machine.h -@@ -0,0 +1,366 @@ -+/* Copyright (C) 2020-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_machine_h -+#define dl_machine_h -+ -+#define ELF_MACHINE_NAME "LoongArch" -+ -+#include -+#include -+#include -+#include -+ -+#ifndef _RTLD_PROLOGUE -+# define _RTLD_PROLOGUE(entry) \ -+ ".globl\t" __STRING (entry) "\n\t" \ -+ ".type\t" __STRING (entry) ", @function\n\t" \ -+ CFI_STARTPROC "\n" \ -+ __STRING (entry) ":\n" -+#endif -+ -+#ifndef _RTLD_EPILOGUE -+# define _RTLD_EPILOGUE(entry) \ -+ CFI_ENDPROC "\n\t" \ -+ ".size\t" __STRING (entry) ", . - " __STRING (entry) "\n" -+#endif -+ -+#define ELF_MACHINE_JMP_SLOT R_LARCH_JUMP_SLOT -+#define ELF_MACHINE_IRELATIVE R_LARCH_IRELATIVE -+ -+#define elf_machine_type_class(type) \ -+ ((ELF_RTYPE_CLASS_PLT * ((type) == ELF_MACHINE_JMP_SLOT \ -+ || (__WORDSIZE == 32 && (type) == R_LARCH_TLS_DTPREL32) \ -+ || (__WORDSIZE == 32 && (type) == R_LARCH_TLS_DTPMOD32) \ -+ || (__WORDSIZE == 32 && (type) == R_LARCH_TLS_TPREL32) \ -+ || (__WORDSIZE == 64 && (type) == R_LARCH_TLS_DTPREL64) \ -+ || (__WORDSIZE == 64 && (type) == R_LARCH_TLS_DTPMOD64) \ -+ || (__WORDSIZE == 64 && (type) == R_LARCH_TLS_TPREL64))) \ -+ | (ELF_RTYPE_CLASS_COPY * ((type) == R_LARCH_COPY))) -+ -+#define ELF_MACHINE_NO_REL 1 -+#define ELF_MACHINE_NO_RELA 0 -+ -+/* Return nonzero iff ELF header is compatible with the running host. */ -+static inline int __attribute_used__ -+elf_machine_matches_host (const ElfW(Ehdr) *ehdr) -+{ -+ /* We can only run LoongArch binaries. */ -+ if (ehdr->e_machine != EM_LOONGARCH) -+ return 0; -+ -+#ifdef _ABILP64 -+ if ((ehdr->e_flags & EF_LARCH_ABI) != EF_LARCH_ABI_LP64) -+#elif defined _ABILPX32 -+ if ((ehdr->e_flags & EF_LARCH_ABI) != EF_LARCH_ABI_LPX32) -+#elif defined _ABILP32 -+ if ((ehdr->e_flags & EF_LARCH_ABI) != EF_LARCH_ABI_LP32) -+#else -+# error "Unknown ABI" -+#endif -+ return 0; -+ -+ return 1; -+} -+ -+/* Runtime address of .got */ -+#define _GLOBAL_OFFSET_TABLE_ ({ \ -+ ElfW(Addr) *r; \ -+ asm ("la.pcrel %0, _GLOBAL_OFFSET_TABLE_":"=r" (r)); \ -+ r; \ -+}) -+ -+/* Return the link-time address of _DYNAMIC. */ -+static inline ElfW(Addr) -+elf_machine_dynamic (void) -+{ -+ return _GLOBAL_OFFSET_TABLE_[0]; -+} -+ -+#define STRINGXP(X) __STRING (X) -+#define STRINGXV(X) STRINGV_ (X) -+#define STRINGV_(...) # __VA_ARGS__ -+ -+/* Return the run-time load address of the shared object. */ -+static inline ElfW(Addr) -+elf_machine_load_address (void) -+{ -+ ElfW(Addr) got_linktime_addr; -+ asm ( -+ "la.got %0, _GLOBAL_OFFSET_TABLE_" -+ /* Link-time address in GOT entry before runtime relocation */ -+ : "=r" (got_linktime_addr) -+ ); -+ return (ElfW(Addr))_GLOBAL_OFFSET_TABLE_ - got_linktime_addr; -+} -+ -+/* Initial entry point code for the dynamic linker. -+ The C function `_dl_start' is the real entry point; -+ its return value is the user program's entry point. */ -+ -+#define RTLD_START asm (\ -+ ".text\n\ -+ " _RTLD_PROLOGUE (ENTRY_POINT) "\ -+ .cfi_label .Ldummy\n\ -+ " CFI_UNDEFINED (1) "\n\ -+ or $a0, $sp, $zero\n\ -+ bl _dl_start\n\ -+ # Stash user entry point in s0.\n\ -+ or $s0, $v0, $zero\n\ -+ # See if we were run as a command with the executable file\n\ -+ # name as an extra leading argument.\n\ -+ la $a0, _dl_skip_args\n\ -+ ld.w $a0, $a0, 0\n\ -+ # Load the original argument count.\n\ -+ ld.d $a1, $sp, 0\n\ -+ # Subtract _dl_skip_args from it.\n\ -+ sub.d $a1, $a1, $a0\n\ -+ # Adjust the stack pointer to skip _dl_skip_args words.\n\ -+ slli.d $a0, $a0, 3\n\ -+ add.d $sp, $sp, $a0\n\ -+ # Save back the modified argument count.\n\ -+ st.d $a1, $sp, 0\n\ -+ # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\ -+ la $a0, _rtld_local\n\ -+ ld.d $a0, $a0, 0\n\ -+ addi.d $a2, $sp, 8\n\ -+ slli.d $a3, $a1, 3\n\ -+ add.d $a3, $a3, $a2\n\ -+ addi.d $a3, $a3, 8\n\ -+ # Adjust $sp for 16-aligned\n\ -+ srli.d $t0, $sp, 4\n\ -+ slli.d $t0, $t0, 4\n\ -+ ori $t1, $sp, 0\n\ -+ addi.d $sp, $t0, -32\n\ -+ st.d $t1, $sp, 24\n\ -+ # Call the function to run the initializers.\n\ -+ bl _dl_init\n\ -+ # Pass our finalizer function to _start.\n\ -+ ld.d $sp, $sp, 24\n\ -+ la $a0, _dl_fini\n\ -+ # Jump to the user entry point.\n\ -+ jirl $zero, $s0, 0\n\ -+ " _RTLD_EPILOGUE (ENTRY_POINT) "\ -+ .previous" \ -+); -+ -+/* Names of the architecture-specific auditing callback functions. */ -+#define ARCH_LA_PLTENTER loongarch_gnu_pltenter -+#define ARCH_LA_PLTEXIT loongarch_gnu_pltexit -+ -+/* Bias .got.plt entry by the offset requested by the PLT header. */ -+#define elf_machine_plt_value(map, reloc, value) (value) -+ -+static inline ElfW(Addr) -+elf_machine_fixup_plt (struct link_map *map, lookup_t t, -+ const ElfW(Sym) *refsym, const ElfW(Sym) *sym, -+ const ElfW(Rela) *reloc, -+ ElfW(Addr) *reloc_addr, ElfW(Addr) value) -+{ -+ return *reloc_addr = value; -+} -+ -+#endif /* !dl_machine_h */ -+ -+#ifdef RESOLVE_MAP -+ -+/* Perform a relocation described by R_INFO at the location pointed to -+ by RELOC_ADDR. SYM is the relocation symbol specified by R_INFO and -+ MAP is the object containing the 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, -+ void *const reloc_addr, int skip_ifunc) -+{ -+ ElfW(Addr) r_info = reloc->r_info; -+ const unsigned long int r_type = ELFW (R_TYPE) (r_info); -+ ElfW(Addr) *addr_field = (ElfW(Addr) *) reloc_addr; -+ const ElfW(Sym) *const __attribute__ ((unused)) refsym = sym; -+ struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); -+ ElfW(Addr) value = 0; -+ if (sym_map != NULL) -+ value = SYMBOL_ADDRESS (sym_map, sym, true) + reloc->r_addend; -+ -+ if (sym != NULL -+ && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0) -+ && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1) -+ && __builtin_expect (!skip_ifunc, 1)) -+ value = ((ElfW(Addr) (*) (int)) value) (GLRO(dl_hwcap)); -+ -+ switch (r_type) -+ { -+#ifndef RTLD_BOOTSTRAP -+ case __WORDSIZE == 64 ? R_LARCH_TLS_DTPMOD64 : R_LARCH_TLS_DTPMOD32: -+ if (sym_map) -+ *addr_field = sym_map->l_tls_modid; -+ break; -+ -+ case __WORDSIZE == 64 ? R_LARCH_TLS_DTPREL64 : R_LARCH_TLS_DTPREL32: -+ if (sym != NULL) -+ *addr_field = TLS_DTPREL_VALUE (sym) + reloc->r_addend; -+ break; -+ -+ case __WORDSIZE == 64 ? R_LARCH_TLS_TPREL64 : R_LARCH_TLS_TPREL32: -+ if (sym != NULL) -+ { -+ CHECK_STATIC_TLS (map, sym_map); -+ *addr_field = TLS_TPREL_VALUE (sym_map, sym) + reloc->r_addend; -+ } -+ break; -+ -+ case R_LARCH_COPY: -+ { -+ if (__glibc_unlikely (sym == NULL)) -+ /* This can happen in trace mode if an object could not be -+ found. */ -+ break; -+ -+ /* Handle TLS copy relocations. */ -+ if (__glibc_unlikely (ELFW (ST_TYPE) (sym->st_info) == STT_TLS)) -+ { -+ /* There's nothing to do if the symbol is in .tbss. */ -+ if (__glibc_likely (sym->st_value >= sym_map->l_tls_initimage_size)) -+ break; -+ value += (ElfW(Addr)) sym_map->l_tls_initimage - sym_map->l_addr; -+ } -+ -+ size_t size = sym->st_size; -+ if (__glibc_unlikely (sym->st_size != refsym->st_size)) -+ { -+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); -+ if (sym->st_size > refsym->st_size) -+ size = refsym->st_size; -+ if (sym->st_size > refsym->st_size || GLRO(dl_verbose)) -+ _dl_error_printf ("\ -+ %s: Symbol `%s' has different size in shared object, consider re-linking\n", -+ rtld_progname ?: "", -+ strtab + refsym->st_name); -+ } -+ -+ memcpy (reloc_addr, (void *)value, size); -+ break; -+ } -+#endif -+ -+#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC -+ case R_LARCH_RELATIVE: -+ { -+# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC -+ /* This is defined in rtld.c, but nowhere in the static libc.a; -+ make the reference weak so static programs can still link. -+ This declaration cannot be done when compiling rtld.c -+ (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the -+ common defn for _dl_rtld_map, which is incompatible with a -+ weak decl in the same file. */ -+# ifndef SHARED -+ weak_extern (GL(dl_rtld_map)); -+# endif -+ if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */ -+# endif -+ *addr_field = map->l_addr + reloc->r_addend; -+ break; -+ } -+#endif -+ -+ case R_LARCH_JUMP_SLOT: -+ case __WORDSIZE == 64 ? R_LARCH_64 : R_LARCH_32: -+ *addr_field = value; -+ break; -+ -+ case R_LARCH_IRELATIVE: -+ value = map->l_addr + reloc->r_addend; -+ value = ((ElfW(Addr) (*) (void)) value) (); -+ *addr_field = value; -+ break; -+ -+ case R_LARCH_NONE: -+ break; -+ -+ default: -+ _dl_reloc_bad_type (map, r_type, 0); -+ break; -+ } -+} -+ -+auto inline void -+__attribute__ ((always_inline)) -+elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc, -+ void *const reloc_addr) -+{ -+ *(ElfW(Addr) *) reloc_addr = l_addr + reloc->r_addend; -+} -+ -+auto inline void -+__attribute__ ((always_inline)) -+elf_machine_lazy_rel (struct link_map *map, ElfW(Addr) l_addr, -+ const ElfW(Rela) *reloc, int skip_ifunc) -+{ -+ ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset); -+ const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info); -+ -+ /* Check for unexpected PLT reloc type. */ -+ if (__glibc_likely (r_type == R_LARCH_JUMP_SLOT)) -+ { -+ if (__glibc_unlikely (map->l_mach.plt == 0)) -+ { -+ if (l_addr) -+ *reloc_addr += l_addr; -+ } -+ else -+ *reloc_addr = map->l_mach.plt; -+ } -+ else if (__glibc_unlikely (r_type == R_LARCH_IRELATIVE)) -+ { -+ ElfW(Addr) *value = (void *) (l_addr + reloc->r_addend); -+ if (__glibc_likely (!skip_ifunc)) -+ value = (ElfW(Addr) *)((ElfW(Addr) (*) (void)) value) (); -+ *reloc_addr = (ElfW(Addr))value; -+ } -+ else -+ _dl_reloc_bad_type (map, r_type, 1); -+} -+ -+/* Set up the loaded object described by L so its stub function -+ will jump to the on-demand fixup code __dl_runtime_resolve. */ -+ -+auto inline int -+__attribute__ ((always_inline)) -+elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) -+{ -+#ifndef RTLD_BOOTSTRAP -+ /* If using PLTs, fill in the first two entries of .got.plt. */ -+ if (l->l_info[DT_JMPREL]) -+ { -+ extern void _dl_runtime_resolve (void) __attribute__ ((visibility ("hidden"))); -+ ElfW(Addr) *gotplt = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]); -+ /* If a library is prelinked but we have to relocate anyway, -+ we have to be able to undo the prelinking of .got.plt. -+ The prelinker saved the address of .plt for us here. */ -+ if (gotplt[1]) -+ l->l_mach.plt = gotplt[1] + l->l_addr; -+ gotplt[0] = (ElfW(Addr)) &_dl_runtime_resolve; -+ gotplt[1] = (ElfW(Addr)) l; -+ } -+#endif -+ -+ return lazy; -+} -+ -+#endif /* RESOLVE_MAP */ -diff --git a/sysdeps/loongarch/dl-tls.h b/sysdeps/loongarch/dl-tls.h -new file mode 100644 -index 00000000..70110c50 ---- /dev/null -+++ b/sysdeps/loongarch/dl-tls.h -@@ -0,0 +1,49 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+ -+/* Type used for the representation of TLS information in the GOT. */ -+typedef struct -+{ -+ unsigned long int ti_module; -+ unsigned long int ti_offset; -+} tls_index; -+ -+/* The thread pointer points to the first static TLS block. */ -+#define TLS_TP_OFFSET 0 -+ -+/* Dynamic thread vector pointers point 0x800 past the start of each -+ TLS block. */ -+//#define TLS_DTV_OFFSET 0x800 -+#define TLS_DTV_OFFSET 0 -+ -+/* Compute the value for a GOTTPREL reloc. */ -+#define TLS_TPREL_VALUE(sym_map, sym) \ -+ ((sym_map)->l_tls_offset + (sym)->st_value - TLS_TP_OFFSET) -+ -+/* Compute the value for a DTPREL reloc. */ -+#define TLS_DTPREL_VALUE(sym) \ -+ ((sym)->st_value - TLS_DTV_OFFSET) -+ -+extern void *__tls_get_addr (tls_index *ti); -+ -+#define GET_ADDR_OFFSET (ti->ti_offset + TLS_DTV_OFFSET) -+#define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET) -+ -+/* Value used for dtv entries for which the allocation is delayed. */ -+#define TLS_DTV_UNALLOCATED ((void *) -1l) -diff --git a/sysdeps/loongarch/dl-trampoline.S b/sysdeps/loongarch/dl-trampoline.S -new file mode 100644 -index 00000000..1f4689e0 ---- /dev/null -+++ b/sysdeps/loongarch/dl-trampoline.S -@@ -0,0 +1,108 @@ -+/* Copyright (C) 2020-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 -+ -+/* Assembler veneer called from the PLT header code for lazy loading. -+ The PLT header passes its own args in t0-t2. */ -+ -+#ifdef __loongarch_soft_float -+# define FRAME_SIZE (-((-10 * SZREG) & ALMASK)) -+#else -+# define FRAME_SIZE (-((-10 * SZREG - 8 * SZFREG) & ALMASK)) -+#endif -+ -+ENTRY (_dl_runtime_resolve) -+ # Save arguments to stack. -+ -+#ifdef __loongarch64 -+ addi.d sp, sp, -FRAME_SIZE -+#elif defined __loongarch32 -+ addi.w sp, sp, -FRAME_SIZE -+#endif -+ -+ REG_S ra, sp, 9*SZREG -+ REG_S a0, sp, 1*SZREG -+ REG_S a1, sp, 2*SZREG -+ REG_S a2, sp, 3*SZREG -+ REG_S a3, sp, 4*SZREG -+ REG_S a4, sp, 5*SZREG -+ REG_S a5, sp, 6*SZREG -+ REG_S a6, sp, 7*SZREG -+ REG_S a7, sp, 8*SZREG -+ -+#ifndef __loongarch_soft_float -+ FREG_S fa0, sp, 10*SZREG + 0*SZFREG -+ FREG_S fa1, sp, 10*SZREG + 1*SZFREG -+ FREG_S fa2, sp, 10*SZREG + 2*SZFREG -+ FREG_S fa3, sp, 10*SZREG + 3*SZFREG -+ FREG_S fa4, sp, 10*SZREG + 4*SZFREG -+ FREG_S fa5, sp, 10*SZREG + 5*SZFREG -+ FREG_S fa6, sp, 10*SZREG + 6*SZFREG -+ FREG_S fa7, sp, 10*SZREG + 7*SZFREG -+#endif -+ -+ # Update .got.plt and obtain runtime address of callee. -+#ifdef __loongarch64 -+ slli.d a1, t1, 1 -+ or a0, t0, zero -+ add.d a1, a1, t1 -+ la a2, _dl_fixup -+ jirl ra, a2, 0 -+ or t1, v0, zero -+#elif defined __loongarch32 -+ slli.w a1, t1, 1 -+ or a0, t0, zero -+ add.w a1, a1, t1 -+ la a2, _dl_fixup -+ jirl ra, a2, 0 -+ or t1, v0, zero -+#endif -+ -+ # Restore arguments from stack. -+ REG_L ra, sp, 9*SZREG -+ REG_L a0, sp, 1*SZREG -+ REG_L a1, sp, 2*SZREG -+ REG_L a2, sp, 3*SZREG -+ REG_L a3, sp, 4*SZREG -+ REG_L a4, sp, 5*SZREG -+ REG_L a5, sp, 6*SZREG -+ REG_L a6, sp, 7*SZREG -+ REG_L a7, sp, 8*SZREG -+ -+#ifndef __loongarch_soft_float -+ FREG_L fa0, sp, 10*SZREG + 0*SZFREG -+ FREG_L fa1, sp, 10*SZREG + 1*SZFREG -+ FREG_L fa2, sp, 10*SZREG + 2*SZFREG -+ FREG_L fa3, sp, 10*SZREG + 3*SZFREG -+ FREG_L fa4, sp, 10*SZREG + 4*SZFREG -+ FREG_L fa5, sp, 10*SZREG + 5*SZFREG -+ FREG_L fa6, sp, 10*SZREG + 6*SZFREG -+ FREG_L fa7, sp, 10*SZREG + 7*SZFREG -+#endif -+ -+#ifdef __loongarch64 -+ addi.d sp, sp, FRAME_SIZE -+#elif defined __loongarch32 -+ addi.w sp, sp, FRAME_SIZE -+#endif -+ -+ # Invoke the callee. -+ jirl zero, t1, 0 -+END (_dl_runtime_resolve) -diff --git a/sysdeps/loongarch/e_sqrtl.c b/sysdeps/loongarch/e_sqrtl.c -new file mode 100644 -index 00000000..65ae7ad8 ---- /dev/null -+++ b/sysdeps/loongarch/e_sqrtl.c -@@ -0,0 +1,39 @@ -+/* long double square root in software floating-point emulation. -+ Copyright (C) 1997-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Richard Henderson (rth@cygnus.com) and -+ Jakub Jelinek (jj@ultra.linux.cz). -+ -+ 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 -+ -+long double -+__ieee754_sqrtl (const long double a) -+{ -+ FP_DECL_EX; -+ FP_DECL_Q(A); FP_DECL_Q(C); -+ long double c; -+ -+ FP_INIT_ROUNDMODE; -+ FP_UNPACK_Q(A, a); -+ FP_SQRT_Q(C, A); -+ FP_PACK_Q(c, C); -+ FP_HANDLE_EXCEPTIONS; -+ return c; -+} -+strong_alias (__ieee754_sqrtl, __sqrtl_finite) -diff --git a/sysdeps/loongarch/elf-init.c b/sysdeps/loongarch/elf-init.c -new file mode 100644 -index 00000000..5f261a9d ---- /dev/null -+++ b/sysdeps/loongarch/elf-init.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/fpu/e_sqrt.c b/sysdeps/loongarch/fpu/e_sqrt.c -new file mode 100644 -index 00000000..dac8696a ---- /dev/null -+++ b/sysdeps/loongarch/fpu/e_sqrt.c -@@ -0,0 +1,29 @@ -+/* Copyright (C) 2002-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Hartvig Ekner , 2002. -+ -+ 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 -+ . */ -+ -+ -+ -+double -+__ieee754_sqrt (double x) -+{ -+ double z; -+ __asm__ ("fsqrt.d %0,%1" : "=f" (z) : "f" (x)); -+ return z; -+} -+strong_alias (__ieee754_sqrt, __sqrt_finite) -+ -diff --git a/sysdeps/loongarch/fpu/e_sqrtf.c b/sysdeps/loongarch/fpu/e_sqrtf.c -new file mode 100644 -index 00000000..706c0494 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/e_sqrtf.c -@@ -0,0 +1,28 @@ -+/* Copyright (C) 2002-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Hartvig Ekner , 2002. -+ -+ 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 -+ . */ -+ -+ -+ -+float -+__ieee754_sqrtf (float x) -+{ -+ float z; -+ __asm__ ("fsqrt.s %0,%1" : "=f" (z) : "f" (x)); -+ return z; -+} -+strong_alias (__ieee754_sqrtf, __sqrtf_finite) -diff --git a/sysdeps/loongarch/fpu/fclrexcpt.c b/sysdeps/loongarch/fpu/fclrexcpt.c -new file mode 100644 -index 00000000..51310d93 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fclrexcpt.c -@@ -0,0 +1,47 @@ -+/* Clear given exceptions in current floating-point environment. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 1998. -+ -+ 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 -+ -+int -+feclearexcept (int excepts) -+{ -+ int cw; -+ -+ /* Mask out unsupported bits/exceptions. */ -+ excepts &= FE_ALL_EXCEPT; -+ -+ /* Read the complete control word. */ -+ _FPU_GETCW (cw); -+ -+ /* Clear exception flag bits and cause bits. If the cause bit is not -+ cleared, the next CTC instruction (just below) will re-generate the -+ exception. */ -+ -+ cw &= ~(excepts | (excepts << CAUSE_SHIFT)); -+ -+ /* Put the new data in effect. */ -+ _FPU_SETCW (cw); -+ -+ /* Success. */ -+ return 0; -+} -+libm_hidden_def (feclearexcept) -diff --git a/sysdeps/loongarch/fpu/fedisblxcpt.c b/sysdeps/loongarch/fpu/fedisblxcpt.c -new file mode 100644 -index 00000000..004b0ecb ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fedisblxcpt.c -@@ -0,0 +1,40 @@ -+/* Disable floating-point exceptions. -+ Copyright (C) 2000-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 2000. -+ -+ 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 -+ -+int -+fedisableexcept (int excepts) -+{ -+ unsigned int new_exc, old_exc; -+ -+ /* Get the current control word. */ -+ _FPU_GETCW (new_exc); -+ -+ old_exc = (new_exc & ENABLE_MASK) << ENABLE_SHIFT; -+ -+ excepts &= FE_ALL_EXCEPT; -+ -+ new_exc &= ~(excepts >> ENABLE_SHIFT); -+ _FPU_SETCW (new_exc); -+ -+ return old_exc; -+} -diff --git a/sysdeps/loongarch/fpu/feenablxcpt.c b/sysdeps/loongarch/fpu/feenablxcpt.c -new file mode 100644 -index 00000000..b8f56625 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/feenablxcpt.c -@@ -0,0 +1,40 @@ -+/* Enable floating-point exceptions. -+ Copyright (C) 2000-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 2000. -+ -+ 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 -+ -+int -+feenableexcept (int excepts) -+{ -+ unsigned int new_exc, old_exc; -+ -+ /* Get the current control word. */ -+ _FPU_GETCW (new_exc); -+ -+ old_exc = (new_exc & ENABLE_MASK) << ENABLE_SHIFT; -+ -+ excepts &= FE_ALL_EXCEPT; -+ -+ new_exc |= excepts >> ENABLE_SHIFT; -+ _FPU_SETCW (new_exc); -+ -+ return old_exc; -+} -diff --git a/sysdeps/loongarch/fpu/fegetenv.c b/sysdeps/loongarch/fpu/fegetenv.c -new file mode 100644 -index 00000000..8e8fa2c5 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fegetenv.c -@@ -0,0 +1,33 @@ -+/* Store current floating-point environment. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 1998. -+ -+ 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 -+ -+int -+__fegetenv (fenv_t *envp) -+{ -+ _FPU_GETCW (*envp); -+ -+ /* Success. */ -+ return 0; -+} -+libm_hidden_def (__fegetenv) -+weak_alias (__fegetenv, fegetenv) -+libm_hidden_weak (fegetenv) -diff --git a/sysdeps/loongarch/fpu/fegetexcept.c b/sysdeps/loongarch/fpu/fegetexcept.c -new file mode 100644 -index 00000000..2c0a1208 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fegetexcept.c -@@ -0,0 +1,33 @@ -+/* Get enabled floating-point exceptions. -+ Copyright (C) 2000-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 2000. -+ -+ 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 -+ -+int -+fegetexcept (void) -+{ -+ unsigned int exc; -+ -+ /* Get the current control word. */ -+ _FPU_GETCW (exc); -+ -+ return (exc & ENABLE_MASK) << ENABLE_SHIFT; -+} -diff --git a/sysdeps/loongarch/fpu/fegetmode.c b/sysdeps/loongarch/fpu/fegetmode.c -new file mode 100644 -index 00000000..e0a5180f ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fegetmode.c -@@ -0,0 +1,27 @@ -+/* Store current floating-point control modes. MIPS version. -+ Copyright (C) 2016-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+ -+int -+fegetmode (femode_t *modep) -+{ -+ _FPU_GETCW (*modep); -+ return 0; -+} -diff --git a/sysdeps/loongarch/fpu/fegetround.c b/sysdeps/loongarch/fpu/fegetround.c -new file mode 100644 -index 00000000..a7ac444a ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fegetround.c -@@ -0,0 +1,35 @@ -+/* Return current rounding direction. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 1998. -+ -+ 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 -+ -+int -+__fegetround (void) -+{ -+ int cw; -+ -+ /* Get control word. */ -+ _FPU_GETCW (cw); -+ -+ return cw & _FPU_RC_MASK; -+} -+libm_hidden_def (__fegetround) -+weak_alias (__fegetround, fegetround) -+libm_hidden_weak (fegetround) -diff --git a/sysdeps/loongarch/fpu/feholdexcpt.c b/sysdeps/loongarch/fpu/feholdexcpt.c -new file mode 100644 -index 00000000..eb9d4764 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/feholdexcpt.c -@@ -0,0 +1,41 @@ -+/* Store current floating-point environment and clear exceptions. -+ Copyright (C) 2000-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 2000. -+ -+ 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 -+ -+int -+__feholdexcept (fenv_t *envp) -+{ -+ fpu_control_t cw; -+ -+ /* Save the current state. */ -+ _FPU_GETCW (cw); -+ envp->__fp_control_register = cw; -+ -+ /* Clear all exception enable bits and flags. */ -+ cw &= ~(_FPU_MASK_V|_FPU_MASK_Z|_FPU_MASK_O|_FPU_MASK_U|_FPU_MASK_I|FE_ALL_EXCEPT); -+ _FPU_SETCW (cw); -+ -+ return 0; -+} -+ -+libm_hidden_def (__feholdexcept) -+weak_alias (__feholdexcept, feholdexcept) -+libm_hidden_weak (feholdexcept) -diff --git a/sysdeps/loongarch/fpu/fenv_libc.h b/sysdeps/loongarch/fpu/fenv_libc.h -new file mode 100644 -index 00000000..f5dd1678 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fenv_libc.h -@@ -0,0 +1,31 @@ -+/* Copyright (C) 2000-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger . -+ -+ 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 _FENV_LIBC_H -+#define _FENV_LIBC_H 1 -+ -+/* Mask for enabling exceptions and for the CAUSE bits. */ -+#define ENABLE_MASK 0x0000001FU -+#define CAUSE_MASK 0x1F000000U -+ -+/* Shift for FE_* flags to get up to the ENABLE bits and the CAUSE bits. */ -+#define ENABLE_SHIFT 16 -+#define CAUSE_SHIFT 8 -+ -+ -+#endif /* _FENV_LIBC_H */ -diff --git a/sysdeps/loongarch/fpu/fesetenv.c b/sysdeps/loongarch/fpu/fesetenv.c -new file mode 100644 -index 00000000..8dee8782 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fesetenv.c -@@ -0,0 +1,44 @@ -+/* Install given floating-point environment. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 1998. -+ -+ 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 -+ -+int -+__fesetenv (const fenv_t *envp) -+{ -+ fpu_control_t cw; -+ -+ /* Read first current state to flush fpu pipeline. */ -+ _FPU_GETCW (cw); -+ -+ if (envp == FE_DFL_ENV) -+ _FPU_SETCW (_FPU_DEFAULT); -+ else if (envp == FE_NOMASK_ENV) -+ _FPU_SETCW (_FPU_IEEE); -+ else -+ _FPU_SETCW (envp->__fp_control_register); -+ -+ /* Success. */ -+ return 0; -+} -+ -+libm_hidden_def (__fesetenv) -+weak_alias (__fesetenv, fesetenv) -+libm_hidden_weak (fesetenv) -diff --git a/sysdeps/loongarch/fpu/fesetexcept.c b/sysdeps/loongarch/fpu/fesetexcept.c -new file mode 100644 -index 00000000..d14febca ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fesetexcept.c -@@ -0,0 +1,32 @@ -+/* Set given exception flags. MIPS version. -+ Copyright (C) 2016-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+ -+int -+fesetexcept (int excepts) -+{ -+ fpu_control_t temp; -+ -+ _FPU_GETCW (temp); -+ temp |= excepts & FE_ALL_EXCEPT; -+ _FPU_SETCW (temp); -+ -+ return 0; -+} -diff --git a/sysdeps/loongarch/fpu/fesetmode.c b/sysdeps/loongarch/fpu/fesetmode.c -new file mode 100644 -index 00000000..8cc5d0b1 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fesetmode.c -@@ -0,0 +1,38 @@ -+/* Install given floating-point control modes. MIPS version. -+ Copyright (C) 2016-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+ -+#define FCSR_STATUS 0x1f1f0000 -+ -+int -+fesetmode (const femode_t *modep) -+{ -+ fpu_control_t cw; -+ -+ _FPU_GETCW (cw); -+ cw &= FCSR_STATUS; -+ if (modep == FE_DFL_MODE) -+ cw |= _FPU_DEFAULT; -+ else -+ cw |= *modep & ~FCSR_STATUS; -+ _FPU_SETCW (cw); -+ -+ return 0; -+} -diff --git a/sysdeps/loongarch/fpu/fesetround.c b/sysdeps/loongarch/fpu/fesetround.c -new file mode 100644 -index 00000000..31fdeab3 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fesetround.c -@@ -0,0 +1,46 @@ -+/* Set current rounding direction. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 1998. -+ -+ 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 -+ -+int -+__fesetround (int round) -+{ -+ fpu_control_t cw; -+ -+ if ((round & ~_FPU_RC_MASK) != 0) -+ /* ROUND is no valid rounding mode. */ -+ return 1; -+ -+ /* Get current state. */ -+ _FPU_GETCW (cw); -+ -+ /* Set rounding bits. */ -+ cw &= ~_FPU_RC_MASK; -+ cw |= round; -+ /* Set new state. */ -+ _FPU_SETCW (cw); -+ -+ return 0; -+} -+ -+libm_hidden_def (__fesetround) -+weak_alias (__fesetround, fesetround) -+libm_hidden_weak (fesetround) -diff --git a/sysdeps/loongarch/fpu/feupdateenv.c b/sysdeps/loongarch/fpu/feupdateenv.c -new file mode 100644 -index 00000000..669bfc3c ---- /dev/null -+++ b/sysdeps/loongarch/fpu/feupdateenv.c -@@ -0,0 +1,45 @@ -+/* Install given floating-point environment and raise exceptions. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 1998. -+ -+ 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 -+ -+int -+__feupdateenv (const fenv_t *envp) -+{ -+ int temp; -+ -+ /* Save current exceptions. */ -+ _FPU_GETCW (temp); -+ temp &= FE_ALL_EXCEPT; -+ -+ /* Install new environment. */ -+ __fesetenv (envp); -+ -+ /* Raise the safed exception. Incidently for us the implementation -+ defined format of the values in objects of type fexcept_t is the -+ same as the ones specified using the FE_* constants. */ -+ __feraiseexcept (temp); -+ -+ /* Success. */ -+ return 0; -+} -+libm_hidden_def (__feupdateenv) -+weak_alias (__feupdateenv, feupdateenv) -+libm_hidden_weak (feupdateenv) -diff --git a/sysdeps/loongarch/fpu/fgetexcptflg.c b/sysdeps/loongarch/fpu/fgetexcptflg.c -new file mode 100644 -index 00000000..1e594e14 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fgetexcptflg.c -@@ -0,0 +1,39 @@ -+/* Store current representation for exceptions. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 1998. -+ -+ 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 -+ -+int -+fegetexceptflag (fexcept_t *flagp, int excepts) -+{ -+ fpu_control_t temp; -+ -+ /* Get the current exceptions. */ -+ _FPU_GETCW (temp); -+ -+ /* We only save the relevant bits here. In particular, care has to be -+ taken with the CAUSE bits, as an inadvertent restore later on could -+ generate unexpected exceptions. */ -+ -+ *flagp = temp & excepts & FE_ALL_EXCEPT; -+ -+ /* Success. */ -+ return 0; -+} -diff --git a/sysdeps/loongarch/fpu/fraiseexcpt.c b/sysdeps/loongarch/fpu/fraiseexcpt.c -new file mode 100644 -index 00000000..2eec053a ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fraiseexcpt.c -@@ -0,0 +1,84 @@ -+/* Raise given exceptions. -+ Copyright (C) 2000-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 2000. -+ -+ 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 -+ -+int -+__feraiseexcept (int excepts) -+{ -+ -+ const float fp_zero = 0.0, fp_one = 1.0, fp_max = FLT_MAX, -+ fp_min = FLT_MIN, fp_1e32 = 1.0e32f, fp_two = 2.0, -+ fp_three = 3.0; -+ -+ /* Raise exceptions represented by EXPECTS. But we must raise only -+ one signal at a time. It is important that if the overflow/underflow -+ exception and the inexact exception are given at the same time, -+ the overflow/underflow exception follows the inexact exception.*/ -+ -+ /* First: invalid exception. */ -+ if (FE_INVALID & excepts) -+ __asm__ __volatile__ ( -+ "fdiv.s $f0,%0,%0\n\t" -+ : -+ : "f" (fp_zero) -+ :"$f0"); -+ -+ /* Next: division by zero. */ -+ if (FE_DIVBYZERO & excepts) -+ __asm__ __volatile__ ( -+ "fdiv.s $f0,%0,%1\n\t" -+ : -+ : "f" (fp_one), "f" (fp_zero) -+ :"$f0"); -+ -+ /* Next: overflow. */ -+ if (FE_OVERFLOW & excepts) -+ /* There's no way to raise overflow without also raising inexact. */ -+ __asm__ __volatile__ ( -+ "fadd.s $f0,%0,%1\n\t" -+ : -+ : "f" (fp_max), "f" (fp_1e32) -+ : "$f0"); -+ -+ /* Next: underflow. */ -+ if (FE_UNDERFLOW & excepts) -+ __asm__ __volatile__ ( -+ "fdiv.s $f0,%0,%1\n\t" -+ : -+ : "f" (fp_min), "f" (fp_three) -+ : "$f0"); -+ -+ /* Last: inexact. */ -+ if (FE_INEXACT & excepts) -+ __asm__ __volatile__ ( -+ "fdiv.s $f0, %0, %1\n\t" -+ : -+ : "f" (fp_two), "f" (fp_three) -+ : "$f0"); -+ -+ /* Success. */ -+ return 0; -+} -+ -+libm_hidden_def (__feraiseexcept) -+weak_alias (__feraiseexcept, feraiseexcept) -+libm_hidden_weak (feraiseexcept) -diff --git a/sysdeps/loongarch/fpu/fsetexcptflg.c b/sysdeps/loongarch/fpu/fsetexcptflg.c -new file mode 100644 -index 00000000..dc447a77 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/fsetexcptflg.c -@@ -0,0 +1,42 @@ -+/* Set floating-point environment exception handling. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Hartvig Ekner , 2002. -+ -+ 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 -+ -+int -+fesetexceptflag (const fexcept_t *flagp, int excepts) -+{ -+ fpu_control_t temp; -+ -+ /* Get the current exceptions. */ -+ _FPU_GETCW (temp); -+ -+ /* Make sure the flags we want restored are legal. */ -+ excepts &= FE_ALL_EXCEPT; -+ -+ /* Now clear the bits called for, and copy them in from flagp. Note that -+ we ignore all non-flag bits from *flagp, so they don't matter. */ -+ temp = (temp & ~excepts) | (*flagp & excepts); -+ -+ _FPU_SETCW (temp); -+ -+ /* Success. */ -+ return 0; -+} -diff --git a/sysdeps/loongarch/fpu/ftestexcept.c b/sysdeps/loongarch/fpu/ftestexcept.c -new file mode 100644 -index 00000000..fa645b26 ---- /dev/null -+++ b/sysdeps/loongarch/fpu/ftestexcept.c -@@ -0,0 +1,33 @@ -+/* Test exception in current environment. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Andreas Jaeger , 1998. -+ -+ 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 -+ -+int -+fetestexcept (int excepts) -+{ -+ int cw; -+ -+ /* Get current control word. */ -+ _FPU_GETCW (cw); -+ -+ return cw & excepts & FE_ALL_EXCEPT; -+} -+libm_hidden_def (fetestexcept) -diff --git a/sysdeps/loongarch/fpu_control.h b/sysdeps/loongarch/fpu_control.h -new file mode 100644 -index 00000000..92474b25 ---- /dev/null -+++ b/sysdeps/loongarch/fpu_control.h -@@ -0,0 +1,111 @@ -+/* FPU control word bits. Mips version. -+ Copyright (C) 1996-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Olaf Flebbe and Ralf Baechle. -+ -+ 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 _FPU_CONTROL_H -+#define _FPU_CONTROL_H -+ -+/* MIPS FPU floating point control register bits. -+ * -+ * 31-25 -> floating point conditions code bits 7-1. These bits are only -+ * available in MIPS IV. -+ * 24 -> flush denormalized results to zero instead of -+ * causing unimplemented operation exception. This bit is only -+ * available for MIPS III and newer. -+ * 23 -> Condition bit -+ * 22-21 -> reserved for architecture implementers -+ * 20 -> reserved (read as 0, write with 0) -+ * 19 -> IEEE 754-2008 non-arithmetic ABS.fmt and NEG.fmt enable -+ * 18 -> IEEE 754-2008 recommended NaN encoding enable -+ * 17 -> cause bit for unimplemented operation -+ * 28 -> cause bit for invalid exception -+ * 27 -> cause bit for division by zero exception -+ * 26 -> cause bit for overflow exception -+ * 25 -> cause bit for underflow exception -+ * 24 -> cause bit for inexact exception -+ * 4 -> enable exception for invalid exception -+ * 3 -> enable exception for division by zero exception -+ * 2 -> enable exception for overflow exception -+ * 1 -> enable exception for underflow exception -+ * 0 -> enable exception for inexact exception -+ * 20 -> flag invalid exception -+ * 19 -> flag division by zero exception -+ * 18 -> flag overflow exception -+ * 17 -> flag underflow exception -+ * 16 -> flag inexact exception -+ * 9-8 -> rounding control -+ * -+ * -+ * Rounding Control: -+ * 00 - rounding to nearest (RN) -+ * 01 - rounding toward zero (RZ) -+ * 10 - rounding (up) toward plus infinity (RP) -+ * 11 - rounding (down)toward minus infinity (RM) -+ */ -+ -+#include -+ -+#ifdef __loongarch_soft_float -+ -+#define _FPU_RESERVED 0xffffffff -+#define _FPU_DEFAULT 0x00000000 -+typedef unsigned int fpu_control_t; -+#define _FPU_GETCW(cw) (cw) = 0 -+#define _FPU_SETCW(cw) (void) (cw) -+extern fpu_control_t __fpu_control; -+ -+#else /* __loongarch_soft_float */ -+ -+/* Masks for interrupts. */ -+#define _FPU_MASK_V 0x10 /* Invalid operation */ -+#define _FPU_MASK_Z 0x08 /* Division by zero */ -+#define _FPU_MASK_O 0x04 /* Overflow */ -+#define _FPU_MASK_U 0x02 /* Underflow */ -+#define _FPU_MASK_I 0x01 /* Inexact operation */ -+ -+/* Flush denormalized numbers to zero. */ -+#define _FPU_FLUSH_TZ 0x1000000 -+ -+/* Rounding control. */ -+#define _FPU_RC_NEAREST 0x000 /* RECOMMENDED */ -+#define _FPU_RC_ZERO 0x100 -+#define _FPU_RC_UP 0x200 -+#define _FPU_RC_DOWN 0x300 -+/* Mask for rounding control. */ -+#define _FPU_RC_MASK 0x300 -+ -+#define _FPU_RESERVED 0x0 -+ -+#define _FPU_DEFAULT 0x0 -+#define _FPU_IEEE 0x1F -+ -+/* Type of the control word. */ -+typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__SI__))); -+ -+/* Macros for accessing the hardware control word. */ -+extern fpu_control_t __mips_fpu_getcw (void) __THROW; -+extern void __mips_fpu_setcw (fpu_control_t) __THROW; -+#define _FPU_GETCW(cw) __asm__ volatile ("movfcsr2gr %0,$r0" : "=r" (cw)) -+#define _FPU_SETCW(cw) __asm__ volatile ("movgr2fcsr $r0,%0" : : "r" (cw)) -+ -+/* Default control word set at startup. */ -+extern fpu_control_t __fpu_control; -+ -+#endif /* __loongarch_soft_float */ -+ -+#endif /* fpu_control.h */ -diff --git a/sysdeps/loongarch/fstat.c b/sysdeps/loongarch/fstat.c -new file mode 100644 -index 00000000..c4504eeb ---- /dev/null -+++ b/sysdeps/loongarch/fstat.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/fstat64.c b/sysdeps/loongarch/fstat64.c -new file mode 100644 -index 00000000..143ca2b0 ---- /dev/null -+++ b/sysdeps/loongarch/fstat64.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/fstatat.c b/sysdeps/loongarch/fstatat.c -new file mode 100644 -index 00000000..0b0a3342 ---- /dev/null -+++ b/sysdeps/loongarch/fstatat.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/fstatat64.c b/sysdeps/loongarch/fstatat64.c -new file mode 100644 -index 00000000..e82b9274 ---- /dev/null -+++ b/sysdeps/loongarch/fstatat64.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/gccframe.h b/sysdeps/loongarch/gccframe.h -new file mode 100644 -index 00000000..5c799c64 ---- /dev/null -+++ b/sysdeps/loongarch/gccframe.h -@@ -0,0 +1,21 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+#define FIRST_PSEUDO_REGISTER 74 -+ -+#include -diff --git a/sysdeps/loongarch/hp-timing.h b/sysdeps/loongarch/hp-timing.h -new file mode 100644 -index 00000000..2d006540 ---- /dev/null -+++ b/sysdeps/loongarch/hp-timing.h -@@ -0,0 +1,40 @@ -+/* High precision, low overhead timing functions. x86-64 version. -+ Copyright (C) 2002-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#ifndef _HP_TIMING_H -+#define _HP_TIMING_H 1 -+ -+/* We always assume having the timestamp register. */ -+#define HP_TIMING_AVAIL (1) -+#define HP_SMALL_TIMING_AVAIL (1) -+ -+/* We indeed have inlined functions. */ -+#define HP_TIMING_INLINE (1) -+ -+/* We use 64bit values for the times. */ -+typedef unsigned long long int hp_timing_t; -+ -+/* Read the cp0 count, this maybe inaccurate. */ -+#define HP_TIMING_NOW(Var) \ -+ ({ unsigned long long int _count; \ -+ asm volatile ("rdtime.d\t%0,$r0" : "=r" (_count)); \ -+ (Var) = _count; }) -+ -+#include -+ -+#endif /* hp-timing.h */ -diff --git a/sysdeps/loongarch/jmpbuf-offsets.h b/sysdeps/loongarch/jmpbuf-offsets.h -new file mode 100644 -index 00000000..bc4c1523 ---- /dev/null -+++ b/sysdeps/loongarch/jmpbuf-offsets.h -@@ -0,0 +1,23 @@ -+/* Copyright (C) 2020-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 -+ -+/* Helper for generic ____longjmp_chk(). */ -+#define JB_FRAME_ADDRESS(buf) \ -+ ((void *) _jmpbuf_sp (buf)) -diff --git a/sysdeps/loongarch/jmpbuf-unwind.h b/sysdeps/loongarch/jmpbuf-unwind.h -new file mode 100644 -index 00000000..c866d910 ---- /dev/null -+++ b/sysdeps/loongarch/jmpbuf-unwind.h -@@ -0,0 +1,46 @@ -+/* Copyright (C) 2020-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 -+ -+/* Test if longjmp to JMPBUF would unwind the frame -+ containing a local variable at ADDRESS. */ -+#define _JMPBUF_UNWINDS(jmpbuf, address, demangle) \ -+ ((void *) (address) < (void *) demangle ((jmpbuf)[0].__sp)) -+ -+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ -+ _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) -+ -+static inline uintptr_t __attribute__ ((unused)) -+_jmpbuf_sp (__jmp_buf regs) -+{ -+ uintptr_t sp = regs[0].__sp; -+#ifdef PTR_DEMANGLE -+ PTR_DEMANGLE (sp); -+#endif -+ return sp; -+} -+ -+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ -+ ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj)) -+ -+/* We use the normal longjmp for unwinding. */ -+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) -diff --git a/sysdeps/loongarch/ldsodefs.h b/sysdeps/loongarch/ldsodefs.h -new file mode 100644 -index 00000000..60b6db58 ---- /dev/null -+++ b/sysdeps/loongarch/ldsodefs.h -@@ -0,0 +1,47 @@ -+/* Run-time dynamic linker data structures for loaded ELF shared objects. -+ Copyright (C) 2011-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#ifndef _LOONGARCH_LDSODEFS_H -+#define _LOONGARCH_LDSODEFS_H 1 -+ -+#include -+ -+struct La_loongarch_regs; -+struct La_loongarch_retval; -+ -+#define ARCH_PLTENTER_MEMBERS \ -+ ElfW(Addr) (*loongarch_gnu_pltenter) (ElfW(Sym) *, unsigned int, \ -+ uintptr_t *, uintptr_t *, \ -+ const struct La_loongarch_regs *, \ -+ unsigned int *, const char *name, \ -+ long int *framesizep); -+ -+#define ARCH_PLTEXIT_MEMBERS \ -+ unsigned int (*loongarch_gnu_pltexit) (ElfW(Sym) *, unsigned int, \ -+ uintptr_t *, uintptr_t *, \ -+ const struct La_loongarch_regs *, \ -+ struct La_loongarch_retval *, \ -+ const char *); -+ -+/* The LoongArch ABI specifies that the dynamic section has to be read-only. */ -+ -+#define DL_RO_DYN_SECTION 1 -+ -+#include_next -+ -+#endif -diff --git a/sysdeps/loongarch/libc-start.h b/sysdeps/loongarch/libc-start.h -new file mode 100644 -index 00000000..d35ed85f ---- /dev/null -+++ b/sysdeps/loongarch/libc-start.h -@@ -0,0 +1,25 @@ -+ /* X86 definitions for libc main startup. -+ Copyright (C) 2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#ifndef SHARED -+# define ARCH_SETUP_IREL() -+# define ARCH_APPLY_IREL() apply_irel () -+# ifndef ARCH_SETUP_TLS -+# define ARCH_SETUP_TLS() __libc_setup_tls () -+# endif -+#endif /* !SHARED */ -diff --git a/sysdeps/loongarch/libc-tls.c b/sysdeps/loongarch/libc-tls.c -new file mode 100644 -index 00000000..0b0590d1 ---- /dev/null -+++ b/sysdeps/loongarch/libc-tls.c -@@ -0,0 +1,32 @@ -+/* Copyright (C) 2020-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 -+ -+/* On LoongArch, linker optimizations are not required, so __tls_get_addr -+ can be called even in statically linked binaries. In this case module -+ must be always 1 and PT_TLS segment exist in the binary, otherwise it -+ would not link. */ -+ -+void * -+__tls_get_addr (tls_index *ti) -+{ -+ dtv_t *dtv = THREAD_DTV (); -+ return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET; -+} -diff --git a/sysdeps/loongarch/linkmap.h b/sysdeps/loongarch/linkmap.h -new file mode 100644 -index 00000000..ac170bb3 ---- /dev/null -+++ b/sysdeps/loongarch/linkmap.h -@@ -0,0 +1,4 @@ -+struct link_map_machine -+ { -+ ElfW(Addr) plt; /* Address of .plt. */ -+ }; -diff --git a/sysdeps/loongarch/lp64/Implies-after b/sysdeps/loongarch/lp64/Implies-after -new file mode 100644 -index 00000000..a8cae95f ---- /dev/null -+++ b/sysdeps/loongarch/lp64/Implies-after -@@ -0,0 +1 @@ -+wordsize-64 -diff --git a/sysdeps/loongarch/lp64/libm-test-ulps b/sysdeps/loongarch/lp64/libm-test-ulps -new file mode 100644 -index 00000000..61be2df6 ---- /dev/null -+++ b/sysdeps/loongarch/lp64/libm-test-ulps -@@ -0,0 +1,2206 @@ -+# Begin of automatic generation -+ -+# Maximal error of functions: -+Function: "acos": -+float: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "acos_downward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "acos_towardzero": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "acos_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "acosh": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "acosh_downward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "acosh_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "acosh_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "asin": -+float: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "asin_downward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "asin_towardzero": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "asin_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "asinh": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "asinh_downward": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "asinh_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "asinh_upward": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "atan": -+float: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "atan2": -+float: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "atan2_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "atan2_towardzero": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "atan2_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "atan_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "atan_towardzero": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "atan_upward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "atanh": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "atanh_downward": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "atanh_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "atanh_upward": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "cabs": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "cabs_downward": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "cabs_towardzero": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "cabs_upward": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "cacos": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "cacos": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "cacos_downward": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "cacos_downward": -+double: 5 -+float: 3 -+idouble: 5 -+ifloat: 3 -+ildouble: 6 -+ldouble: 6 -+ -+Function: Real part of "cacos_towardzero": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "cacos_towardzero": -+double: 4 -+float: 2 -+idouble: 4 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Real part of "cacos_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "cacos_upward": -+double: 5 -+float: 5 -+idouble: 5 -+ifloat: 5 -+ildouble: 7 -+ldouble: 7 -+ -+Function: Real part of "cacosh": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "cacosh": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "cacosh_downward": -+double: 4 -+float: 2 -+idouble: 4 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Imaginary part of "cacosh_downward": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Real part of "cacosh_towardzero": -+double: 4 -+float: 2 -+idouble: 4 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Imaginary part of "cacosh_towardzero": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "cacosh_upward": -+double: 4 -+float: 3 -+idouble: 4 -+ifloat: 3 -+ildouble: 6 -+ldouble: 6 -+ -+Function: Imaginary part of "cacosh_upward": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "carg": -+float: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "carg_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "carg_towardzero": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "carg_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "casin": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "casin": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "casin_downward": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "casin_downward": -+double: 5 -+float: 3 -+idouble: 5 -+ifloat: 3 -+ildouble: 6 -+ldouble: 6 -+ -+Function: Real part of "casin_towardzero": -+double: 3 -+float: 1 -+idouble: 3 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "casin_towardzero": -+double: 4 -+float: 2 -+idouble: 4 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Real part of "casin_upward": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "casin_upward": -+double: 5 -+float: 5 -+idouble: 5 -+ifloat: 5 -+ildouble: 7 -+ldouble: 7 -+ -+Function: Real part of "casinh": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "casinh": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "casinh_downward": -+double: 5 -+float: 3 -+idouble: 5 -+ifloat: 3 -+ildouble: 6 -+ldouble: 6 -+ -+Function: Imaginary part of "casinh_downward": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "casinh_towardzero": -+double: 4 -+float: 2 -+idouble: 4 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Imaginary part of "casinh_towardzero": -+double: 3 -+float: 1 -+idouble: 3 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "casinh_upward": -+double: 5 -+float: 5 -+idouble: 5 -+ifloat: 5 -+ildouble: 7 -+ldouble: 7 -+ -+Function: Imaginary part of "casinh_upward": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "catan": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Imaginary part of "catan": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "catan_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "catan_downward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "catan_towardzero": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "catan_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "catan_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "catan_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "catanh": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Imaginary part of "catanh": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "catanh_downward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "catanh_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "catanh_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "catanh_towardzero": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "catanh_upward": -+double: 4 -+float: 4 -+idouble: 4 -+ifloat: 4 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Imaginary part of "catanh_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "cbrt": -+double: 3 -+float: 1 -+idouble: 3 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "cbrt_downward": -+double: 4 -+float: 1 -+idouble: 4 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "cbrt_towardzero": -+double: 3 -+float: 1 -+idouble: 3 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "cbrt_upward": -+double: 5 -+float: 1 -+idouble: 5 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "ccos": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Imaginary part of "ccos": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "ccos_downward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "ccos_downward": -+double: 2 -+float: 3 -+idouble: 2 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "ccos_towardzero": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "ccos_towardzero": -+double: 2 -+float: 3 -+idouble: 2 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "ccos_upward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "ccos_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "ccosh": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Imaginary part of "ccosh": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "ccosh_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "ccosh_downward": -+double: 2 -+float: 3 -+idouble: 2 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "ccosh_towardzero": -+double: 1 -+float: 3 -+idouble: 1 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "ccosh_towardzero": -+double: 2 -+float: 3 -+idouble: 2 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "ccosh_upward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "ccosh_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "cexp": -+double: 2 -+float: 1 -+idouble: 2 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Imaginary part of "cexp": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "cexp_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "cexp_downward": -+double: 1 -+float: 3 -+idouble: 1 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "cexp_towardzero": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "cexp_towardzero": -+double: 1 -+float: 3 -+idouble: 1 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "cexp_upward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "cexp_upward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "clog": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "clog": -+float: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "clog10": -+double: 3 -+float: 4 -+idouble: 3 -+ifloat: 4 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "clog10": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "clog10_downward": -+double: 5 -+float: 5 -+idouble: 5 -+ifloat: 5 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "clog10_downward": -+double: 2 -+float: 4 -+idouble: 2 -+ifloat: 4 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "clog10_towardzero": -+double: 5 -+float: 5 -+idouble: 5 -+ifloat: 5 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Imaginary part of "clog10_towardzero": -+double: 2 -+float: 4 -+idouble: 2 -+ifloat: 4 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "clog10_upward": -+double: 6 -+float: 5 -+idouble: 6 -+ifloat: 5 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Imaginary part of "clog10_upward": -+double: 2 -+float: 4 -+idouble: 2 -+ifloat: 4 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "clog_downward": -+double: 4 -+float: 3 -+idouble: 4 -+ifloat: 3 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "clog_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "clog_towardzero": -+double: 4 -+float: 4 -+idouble: 4 -+ifloat: 4 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "clog_towardzero": -+double: 1 -+float: 3 -+idouble: 1 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "clog_upward": -+double: 4 -+float: 3 -+idouble: 4 -+ifloat: 3 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Imaginary part of "clog_upward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "cos": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "cos_downward": -+double: 1 -+idouble: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "cos_towardzero": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "cos_upward": -+double: 1 -+idouble: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "cosh": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "cosh_downward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 2 -+ -+Function: "cosh_towardzero": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 2 -+ -+Function: "cosh_upward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 1 -+ldouble: 3 -+ -+Function: Real part of "cpow": -+double: 2 -+float: 5 -+idouble: 2 -+ifloat: 5 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Imaginary part of "cpow": -+float: 2 -+ifloat: 2 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "cpow_downward": -+double: 4 -+float: 8 -+idouble: 4 -+ifloat: 8 -+ildouble: 6 -+ldouble: 6 -+ -+Function: Imaginary part of "cpow_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "cpow_towardzero": -+double: 4 -+float: 8 -+idouble: 4 -+ifloat: 8 -+ildouble: 6 -+ldouble: 6 -+ -+Function: Imaginary part of "cpow_towardzero": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "cpow_upward": -+double: 4 -+float: 1 -+idouble: 4 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "cpow_upward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "csin": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Imaginary part of "csin": -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "csin_downward": -+double: 2 -+float: 3 -+idouble: 2 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "csin_downward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "csin_towardzero": -+double: 2 -+float: 3 -+idouble: 2 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "csin_towardzero": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "csin_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "csin_upward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "csinh": -+float: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Imaginary part of "csinh": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: Real part of "csinh_downward": -+double: 2 -+float: 1 -+idouble: 2 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "csinh_downward": -+double: 2 -+float: 3 -+idouble: 2 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "csinh_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "csinh_towardzero": -+double: 2 -+float: 3 -+idouble: 2 -+ifloat: 3 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "csinh_upward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "csinh_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "csqrt": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Imaginary part of "csqrt": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: Real part of "csqrt_downward": -+double: 5 -+float: 4 -+idouble: 5 -+ifloat: 4 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Imaginary part of "csqrt_downward": -+double: 4 -+float: 3 -+idouble: 4 -+ifloat: 3 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "csqrt_towardzero": -+double: 4 -+float: 3 -+idouble: 4 -+ifloat: 3 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "csqrt_towardzero": -+double: 4 -+float: 3 -+idouble: 4 -+ifloat: 3 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "csqrt_upward": -+double: 5 -+float: 4 -+idouble: 5 -+ifloat: 4 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Imaginary part of "csqrt_upward": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "ctan": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "ctan": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "ctan_downward": -+double: 6 -+float: 5 -+idouble: 6 -+ifloat: 5 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Imaginary part of "ctan_downward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Real part of "ctan_towardzero": -+double: 5 -+float: 2 -+idouble: 5 -+ifloat: 2 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Imaginary part of "ctan_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Real part of "ctan_upward": -+double: 2 -+float: 4 -+idouble: 2 -+ifloat: 4 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Imaginary part of "ctan_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Real part of "ctanh": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Imaginary part of "ctanh": -+double: 2 -+float: 1 -+idouble: 2 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "ctanh_downward": -+double: 4 -+float: 2 -+idouble: 4 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Imaginary part of "ctanh_downward": -+double: 6 -+float: 5 -+idouble: 6 -+ifloat: 5 -+ildouble: 4 -+ldouble: 4 -+ -+Function: Real part of "ctanh_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Imaginary part of "ctanh_towardzero": -+double: 5 -+float: 2 -+idouble: 5 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: Real part of "ctanh_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: Imaginary part of "ctanh_upward": -+double: 2 -+float: 3 -+idouble: 2 -+ifloat: 3 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "erf": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "erf_downward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "erf_towardzero": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "erf_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "erfc": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "erfc_downward": -+double: 3 -+float: 4 -+idouble: 3 -+ifloat: 4 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "erfc_towardzero": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "erfc_upward": -+double: 3 -+float: 4 -+idouble: 3 -+ifloat: 4 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "exp": -+ildouble: 1 -+ldouble: 1 -+ -+Function: "exp10": -+double: 2 -+idouble: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "exp10_downward": -+double: 2 -+float: 1 -+idouble: 2 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "exp10_towardzero": -+double: 2 -+float: 1 -+idouble: 2 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "exp10_upward": -+double: 2 -+float: 1 -+idouble: 2 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "exp2": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "exp2_downward": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "exp2_towardzero": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "exp2_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "exp_downward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ -+Function: "exp_towardzero": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ -+Function: "exp_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ -+Function: "expm1": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "expm1_downward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "expm1_towardzero": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "expm1_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "gamma": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "gamma_downward": -+double: 4 -+float: 4 -+idouble: 4 -+ifloat: 4 -+ildouble: 8 -+ldouble: 8 -+ -+Function: "gamma_towardzero": -+double: 4 -+float: 3 -+idouble: 4 -+ifloat: 3 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "gamma_upward": -+double: 4 -+float: 5 -+idouble: 4 -+ifloat: 5 -+ildouble: 8 -+ldouble: 8 -+ -+Function: "hypot": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "hypot_downward": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "hypot_towardzero": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "hypot_upward": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "j0": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "j0_downward": -+double: 2 -+float: 4 -+idouble: 2 -+ifloat: 4 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "j0_towardzero": -+double: 2 -+float: 1 -+idouble: 2 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "j0_upward": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "j1": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "j1_downward": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "j1_towardzero": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "j1_upward": -+double: 3 -+float: 4 -+idouble: 3 -+ifloat: 4 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "jn": -+double: 4 -+float: 4 -+idouble: 4 -+ifloat: 4 -+ildouble: 7 -+ldouble: 7 -+ -+Function: "jn_downward": -+double: 4 -+float: 5 -+idouble: 4 -+ifloat: 5 -+ildouble: 8 -+ldouble: 8 -+ -+Function: "jn_towardzero": -+double: 4 -+float: 5 -+idouble: 4 -+ifloat: 5 -+ildouble: 8 -+ldouble: 8 -+ -+Function: "jn_upward": -+double: 5 -+float: 4 -+idouble: 5 -+ifloat: 4 -+ildouble: 7 -+ldouble: 7 -+ -+Function: "lgamma": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "lgamma_downward": -+double: 4 -+float: 4 -+idouble: 4 -+ifloat: 4 -+ildouble: 8 -+ldouble: 8 -+ -+Function: "lgamma_towardzero": -+double: 4 -+float: 3 -+idouble: 4 -+ifloat: 3 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "lgamma_upward": -+double: 4 -+float: 5 -+idouble: 4 -+ifloat: 5 -+ildouble: 8 -+ldouble: 8 -+ -+Function: "log": -+ildouble: 1 -+ldouble: 1 -+ -+Function: "log10": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "log10_downward": -+double: 2 -+float: 3 -+idouble: 2 -+ifloat: 3 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "log10_towardzero": -+double: 2 -+float: 1 -+idouble: 2 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "log10_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "log1p": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "log1p_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "log1p_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "log1p_upward": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "log2": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "log2_downward": -+double: 3 -+idouble: 3 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "log2_towardzero": -+double: 2 -+idouble: 2 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "log2_upward": -+double: 3 -+idouble: 3 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "log_downward": -+ildouble: 1 -+ldouble: 1 -+ -+Function: "log_towardzero": -+ildouble: 2 -+ldouble: 2 -+ -+Function: "log_upward": -+double: 1 -+idouble: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "pow": -+double: 1 -+idouble: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "pow_downward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "pow_towardzero": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "pow_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "sin": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "sin_downward": -+double: 1 -+idouble: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "sin_towardzero": -+double: 1 -+idouble: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "sin_upward": -+double: 1 -+idouble: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "sincos": -+double: 1 -+idouble: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "sincos_downward": -+double: 1 -+idouble: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "sincos_towardzero": -+double: 1 -+idouble: 1 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "sincos_upward": -+double: 1 -+idouble: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "sinh": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "sinh_downward": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "sinh_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "sinh_upward": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "tan": -+float: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "tan_downward": -+double: 1 -+float: 2 -+idouble: 1 -+ifloat: 2 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "tan_towardzero": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "tan_upward": -+double: 1 -+float: 1 -+idouble: 1 -+ifloat: 1 -+ildouble: 1 -+ldouble: 1 -+ -+Function: "tanh": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "tanh_downward": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "tanh_towardzero": -+double: 2 -+float: 2 -+idouble: 2 -+ifloat: 2 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "tanh_upward": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "tgamma": -+double: 5 -+float: 4 -+idouble: 5 -+ifloat: 4 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "tgamma_downward": -+double: 5 -+float: 5 -+idouble: 5 -+ifloat: 5 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "tgamma_towardzero": -+double: 5 -+float: 4 -+idouble: 5 -+ifloat: 4 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "tgamma_upward": -+double: 4 -+float: 4 -+idouble: 4 -+ifloat: 4 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "y0": -+double: 2 -+float: 1 -+idouble: 2 -+ifloat: 1 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "y0_downward": -+double: 3 -+float: 4 -+idouble: 3 -+ifloat: 4 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "y0_towardzero": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "y0_upward": -+double: 2 -+float: 5 -+idouble: 2 -+ifloat: 5 -+ildouble: 3 -+ldouble: 3 -+ -+Function: "y1": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "y1_downward": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 4 -+ldouble: 4 -+ -+Function: "y1_towardzero": -+double: 3 -+float: 2 -+idouble: 3 -+ifloat: 2 -+ildouble: 2 -+ldouble: 2 -+ -+Function: "y1_upward": -+double: 5 -+float: 2 -+idouble: 5 -+ifloat: 2 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "yn": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "yn_downward": -+double: 3 -+float: 4 -+idouble: 3 -+ifloat: 4 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "yn_towardzero": -+double: 3 -+float: 3 -+idouble: 3 -+ifloat: 3 -+ildouble: 5 -+ldouble: 5 -+ -+Function: "yn_upward": -+double: 4 -+float: 5 -+idouble: 4 -+ifloat: 5 -+ildouble: 5 -+ldouble: 5 -+ -+# end of automatic generation -diff --git a/sysdeps/loongarch/lp64/libm-test-ulps-name b/sysdeps/loongarch/lp64/libm-test-ulps-name -new file mode 100644 -index 00000000..ce02281e ---- /dev/null -+++ b/sysdeps/loongarch/lp64/libm-test-ulps-name -@@ -0,0 +1 @@ -+LoongArch 64-bit -diff --git a/sysdeps/loongarch/lp64/memcpy.S b/sysdeps/loongarch/lp64/memcpy.S -new file mode 100644 -index 00000000..2dc7a779 ---- /dev/null -+++ b/sysdeps/loongarch/lp64/memcpy.S -@@ -0,0 +1,402 @@ -+#ifdef _LIBC -+#include -+#include -+#include -+#else -+#include -+#include -+#endif -+ -+/* Allow the routine to be named something else if desired. */ -+#ifndef MEMCPY_NAME -+#define MEMCPY_NAME memcpy -+#endif -+ -+#define LD_64(reg, n) \ -+ ld.d t0, reg, n; \ -+ ld.d t1, reg, n+8; \ -+ ld.d t2, reg, n+16; \ -+ ld.d t3, reg, n+24; \ -+ ld.d t4, reg, n+32; \ -+ ld.d t5, reg, n+40; \ -+ ld.d t6, reg, n+48; \ -+ ld.d t7, reg, n+56; -+ -+ -+#define ST_64(reg, n) \ -+ st.d t0, reg, n; \ -+ st.d t1, reg, n+8; \ -+ st.d t2, reg, n+16; \ -+ st.d t3, reg, n+24; \ -+ st.d t4, reg, n+32; \ -+ st.d t5, reg, n+40; \ -+ st.d t6, reg, n+48; \ -+ st.d t7, reg, n+56; -+ -+#define LDST_1024 \ -+ LD_64(a1, 0); \ -+ ST_64(a0, 0); \ -+ LD_64(a1, 64); \ -+ ST_64(a0, 64); \ -+ LD_64(a1, 128); \ -+ ST_64(a0, 128); \ -+ LD_64(a1, 192); \ -+ ST_64(a0, 192); \ -+ LD_64(a1, 256); \ -+ ST_64(a0, 256); \ -+ LD_64(a1, 320); \ -+ ST_64(a0, 320); \ -+ LD_64(a1, 384); \ -+ ST_64(a0, 384); \ -+ LD_64(a1, 448); \ -+ ST_64(a0, 448); \ -+ LD_64(a1, 512); \ -+ ST_64(a0, 512); \ -+ LD_64(a1, 576); \ -+ ST_64(a0, 576); \ -+ LD_64(a1, 640); \ -+ ST_64(a0, 640); \ -+ LD_64(a1, 704); \ -+ ST_64(a0, 704); \ -+ LD_64(a1, 768); \ -+ ST_64(a0, 768); \ -+ LD_64(a1, 832); \ -+ ST_64(a0, 832); \ -+ LD_64(a1, 896); \ -+ ST_64(a0, 896); \ -+ LD_64(a1, 960); \ -+ ST_64(a0, 960); -+ -+#ifdef ANDROID_CHANGES -+LEAF(MEMCPY_NAME, 0) -+#else -+LEAF(MEMCPY_NAME) -+#endif -+ -+//1st var: dest ptr: void *str1 $r4 -+//2nd var: src ptr: void *str2 $r5 -+//3rd var: size_t num -+//t0~t9 registers as temp -+ -+ add.d a4, a1, a2 -+ add.d a3, a0, a2 -+ move t8, a0 -+ move a5, a1 -+ srai.d a6, a2, 4 #num/16 -+ beqz a6, less_16bytes #num<16 -+ slti a6, a2, 137 -+ beqz a6, more_137bytes #num>137 -+ srai.d a6, a2, 6 -+ beqz a6, less_64bytes #num<64 -+ -+ srli.d a0, a0, 3 -+ slli.d a0, a0, 3 -+ addi.d a0, a0, 0x8 -+ sub.d a7, t8, a0 -+ ld.d t0, a1, 0 -+ sub.d a1, a1, a7 -+ st.d t0, t8, 0 -+ -+ add.d a7, a7, a2 -+ addi.d a7, a7, -0x20 -+loop_32: -+ ld.d t0, a1, 0 -+ ld.d t1, a1, 8 -+ ld.d t2, a1, 16 -+ ld.d t3, a1, 24 -+ st.d t0, a0, 0 -+ st.d t1, a0, 8 -+ st.d t2, a0, 16 -+ st.d t3, a0, 24 -+ -+ addi.d a0, a0, 0x20 -+ addi.d a1, a1, 0x20 -+ addi.d a7, a7, -0x20 -+ blt zero, a7, loop_32 -+ -+ ld.d t4, a4, -32 -+ ld.d t5, a4, -24 -+ ld.d t6, a4, -16 -+ ld.d t7, a4, -8 -+ st.d t4, a3, -32 -+ st.d t5, a3, -24 -+ st.d t6, a3, -16 -+ st.d t7, a3, -8 -+ -+ move v0, t8 -+ jr ra -+ -+less_64bytes: -+ srai.d a6, a2, 5 -+ beqz a6, less_32bytes -+ -+ ld.d t0, a1, 0 -+ ld.d t1, a1, 8 -+ ld.d t2, a1, 16 -+ ld.d t3, a1, 24 -+ ld.d t4, a4, -32 -+ ld.d t5, a4, -24 -+ ld.d t6, a4, -16 -+ ld.d t7, a4, -8 -+ st.d t0, a0, 0 -+ st.d t1, a0, 8 -+ st.d t2, a0, 16 -+ st.d t3, a0, 24 -+ st.d t4, a3, -32 -+ st.d t5, a3, -24 -+ st.d t6, a3, -16 -+ st.d t7, a3, -8 -+ -+ jr ra -+ -+less_32bytes: -+ ld.d t0, a1, 0 -+ ld.d t1, a1, 8 -+ ld.d t2, a4, -16 -+ ld.d t3, a4, -8 -+ st.d t0, a0, 0 -+ st.d t1, a0, 8 -+ st.d t2, a3, -16 -+ st.d t3, a3, -8 -+ -+ jr ra -+ -+less_16bytes: -+ srai.d a6, a2, 3 #num/8 -+ beqz a6, less_8bytes -+ -+ ld.d t0, a1, 0 -+ ld.d t1, a4, -8 -+ st.d t0, a0, 0 -+ st.d t1, a3, -8 -+ -+ jr ra -+ -+less_8bytes: -+ srai.d a6, a2, 2 -+ beqz a6, less_4bytes -+ -+ ld.w t0, a1, 0 -+ ld.w t1, a4, -4 -+ st.w t0, a0, 0 -+ st.w t1, a3, -4 -+ -+ jr ra -+ -+less_4bytes: -+ srai.d a6, a2, 1 -+ beqz a6, less_2bytes -+ -+ ld.h t0, a1, 0 -+ ld.h t1, a4, -2 -+ st.h t0, a0, 0 -+ st.h t1, a3, -2 -+ -+ jr ra -+ -+less_2bytes: -+ beqz a2, less_1bytes -+ -+ ld.b t0, a1, 0 -+ st.b t0, a0, 0 -+ -+ jr ra -+ -+less_1bytes: -+ jr ra -+ -+more_137bytes: -+ li.w a6, 64 -+ andi t1, a0, 7 -+ srli.d a0, a0, 3 -+ andi t2, a2, 7 -+ slli.d a0, a0, 3 -+ add.d t1, t1, t2 -+ beqz t1, all_align -+ beq a0, t8, start_over -+ addi.d a0, a0, 0x8 -+ sub.d a7, t8, a0 -+ sub.d a1, a1, a7 -+ add.d a2, a7, a2 -+ -+start_unalign_proc: -+ ld.d t0, a5, 0 -+ slli.d t0, t0, 8 -+ pcaddi t1, 18 -+ slli.d t2, a7, 3 -+ add.d t1, t1, t2 -+ jirl zero, t1, 0 -+ -+start_7_unalign: -+ srli.d t0, t0, 8 -+ st.b t0, a0, -7 -+start_6_unalign: -+ srli.d t0, t0, 8 -+ st.b t0, a0, -6 -+start_5_unalign: -+ srli.d t0, t0, 8 -+ st.b t0, a0, -5 -+start_4_unalign: -+ srli.d t0, t0, 8 -+ st.b t0, a0, -4 -+start_3_unalign: -+ srli.d t0, t0, 8 -+ st.b t0, a0, -3 -+start_2_unalign: -+ srli.d t0, t0, 8 -+ st.b t0, a0, -2 -+start_1_unalign: -+ srli.d t0, t0, 8 -+ st.b t0, a0, -1 -+start_over: -+ -+ addi.d a2, a2, -0x80 -+ blt a2, zero, end_unalign_proc -+ -+loop_less: -+ LD_64(a1, 0) -+ ST_64(a0, 0) -+ LD_64(a1, 64) -+ ST_64(a0, 64) -+ -+ addi.d a0, a0, 0x80 -+ addi.d a1, a1, 0x80 -+ addi.d a2, a2, -0x80 -+ bge a2, zero, loop_less -+ -+end_unalign_proc: -+ addi.d a2, a2, 0x80 -+ -+ pcaddi t1, 34 -+ andi t2, a2, 0x78 -+ sub.d t1, t1, t2 -+ jirl zero, t1, 0 -+ -+end_120_128_unalign: -+ ld.d t0, a1, 112 -+ st.d t0, a0, 112 -+end_112_120_unalign: -+ ld.d t0, a1, 104 -+ st.d t0, a0, 104 -+end_104_112_unalign: -+ ld.d t0, a1, 96 -+ st.d t0, a0, 96 -+end_96_104_unalign: -+ ld.d t0, a1, 88 -+ st.d t0, a0, 88 -+end_88_96_unalign: -+ ld.d t0, a1, 80 -+ st.d t0, a0, 80 -+end_80_88_unalign: -+ ld.d t0, a1, 72 -+ st.d t0, a0, 72 -+end_72_80_unalign: -+ ld.d t0, a1, 64 -+ st.d t0, a0, 64 -+end_64_72_unalign: -+ ld.d t0, a1, 56 -+ st.d t0, a0, 56 -+end_56_64_unalign: -+ ld.d t0, a1, 48 -+ st.d t0, a0, 48 -+end_48_56_unalign: -+ ld.d t0, a1, 40 -+ st.d t0, a0, 40 -+end_40_48_unalign: -+ ld.d t0, a1, 32 -+ st.d t0, a0, 32 -+end_32_40_unalign: -+ ld.d t0, a1, 24 -+ st.d t0, a0, 24 -+end_24_32_unalign: -+ ld.d t0, a1, 16 -+ st.d t0, a0, 16 -+end_16_24_unalign: -+ ld.d t0, a1, 8 -+ st.d t0, a0, 8 -+end_8_16_unalign: -+ ld.d t0, a1, 0 -+ st.d t0, a0, 0 -+end_0_8_unalign: -+ -+ mod.d t0, a3, a6 -+ srli.d t1, t0, 3 -+ slti t0, t0, 1 -+ add.d t0, t0, t1 -+ blt zero, t0, end_8_without_cross_cache_line -+ -+ andi a2, a2, 0x7 -+ pcaddi t1, 18 -+ slli.d a2, a2, 3 -+ sub.d t1, t1, a2 -+ jirl zero, t1, 0 -+ -+end_7_unalign: -+ ld.b t0, a4, -7 -+ st.b t0, a3, -7 -+end_6_unalign: -+ ld.b t0, a4, -6 -+ st.b t0, a3, -6 -+end_5_unalign: -+ ld.b t0, a4, -5 -+ st.b t0, a3, -5 -+end_4_unalign: -+ ld.b t0, a4, -4 -+ st.b t0, a3, -4 -+end_3_unalign: -+ ld.b t0, a4, -3 -+ st.b t0, a3, -3 -+end_2_unalign: -+ ld.b t0, a4, -2 -+ st.b t0, a3, -2 -+end_1_unalign: -+ ld.b t0, a4, -1 -+ st.b t0, a3, -1 -+end: -+ -+ move v0, t8 -+ jr ra -+ -+all_align: -+ addi.d a2, a2, -0x20 -+ -+align_loop_less: -+ ld.d t0, a1, 0 -+ ld.d t1, a1, 8 -+ ld.d t2, a1, 16 -+ ld.d t3, a1, 24 -+ st.d t0, a0, 0 -+ st.d t1, a0, 8 -+ st.d t2, a0, 16 -+ st.d t3, a0, 24 -+ -+ addi.d a0, a0, 0x20 -+ addi.d a1, a1, 0x20 -+ addi.d a2, a2, -0x20 -+ blt zero, a2, align_loop_less -+ -+ ld.d t4, a4, -32 -+ ld.d t5, a4, -24 -+ ld.d t6, a4, -16 -+ ld.d t7, a4, -8 -+ st.d t4, a3, -32 -+ st.d t5, a3, -24 -+ st.d t6, a3, -16 -+ st.d t7, a3, -8 -+ -+ move v0, t8 -+ jr ra -+ -+end_8_without_cross_cache_line: -+ ld.d t0, a4, -8 -+ st.d t0, a3, -8 -+ -+ move v0, t8 -+ jr ra -+ -+END(MEMCPY_NAME) -+#ifndef ANDROID_CHANGES -+#ifdef _LIBC -+libc_hidden_builtin_def (MEMCPY_NAME) -+#endif -+#endif -diff --git a/sysdeps/loongarch/lp64/memmove.S b/sysdeps/loongarch/lp64/memmove.S -new file mode 100644 -index 00000000..f87d036b ---- /dev/null -+++ b/sysdeps/loongarch/lp64/memmove.S -@@ -0,0 +1,476 @@ -+#ifdef _LIBC -+#include -+#include -+#include -+#else -+#include -+#include -+#endif -+ -+/* Allow the routine to be named something else if desired. */ -+#ifndef MEMMOVE_NAME -+#define MEMMOVE_NAME memmove -+#endif -+ -+#define LD_64(reg, n) \ -+ ld.d t0, reg, n; \ -+ ld.d t1, reg, n+8; \ -+ ld.d t2, reg, n+16; \ -+ ld.d t3, reg, n+24; \ -+ ld.d t4, reg, n+32; \ -+ ld.d t5, reg, n+40; \ -+ ld.d t6, reg, n+48; \ -+ ld.d t7, reg, n+56; -+ -+ -+#define ST_64(reg, n) \ -+ st.d t0, reg, n; \ -+ st.d t1, reg, n+8; \ -+ st.d t2, reg, n+16; \ -+ st.d t3, reg, n+24; \ -+ st.d t4, reg, n+32; \ -+ st.d t5, reg, n+40; \ -+ st.d t6, reg, n+48; \ -+ st.d t7, reg, n+56; -+ -+#define LDST_1024 \ -+ LD_64(a1, 0); \ -+ ST_64(a0, 0); \ -+ LD_64(a1, 64); \ -+ ST_64(a0, 64); \ -+ LD_64(a1, 128); \ -+ ST_64(a0, 128); \ -+ LD_64(a1, 192); \ -+ ST_64(a0, 192); \ -+ LD_64(a1, 256); \ -+ ST_64(a0, 256); \ -+ LD_64(a1, 320); \ -+ ST_64(a0, 320); \ -+ LD_64(a1, 384); \ -+ ST_64(a0, 384); \ -+ LD_64(a1, 448); \ -+ ST_64(a0, 448); \ -+ LD_64(a1, 512); \ -+ ST_64(a0, 512); \ -+ LD_64(a1, 576); \ -+ ST_64(a0, 576); \ -+ LD_64(a1, 640); \ -+ ST_64(a0, 640); \ -+ LD_64(a1, 704); \ -+ ST_64(a0, 704); \ -+ LD_64(a1, 768); \ -+ ST_64(a0, 768); \ -+ LD_64(a1, 832); \ -+ ST_64(a0, 832); \ -+ LD_64(a1, 896); \ -+ ST_64(a0, 896); \ -+ LD_64(a1, 960); \ -+ ST_64(a0, 960); -+ -+#define LDST_1024_BACK \ -+ LD_64(a4, -64); \ -+ ST_64(a3, -64); \ -+ LD_64(a4, -128); \ -+ ST_64(a3, -128); \ -+ LD_64(a4, -192); \ -+ ST_64(a3, -192); \ -+ LD_64(a4, -256); \ -+ ST_64(a3, -256); \ -+ LD_64(a4, -320); \ -+ ST_64(a3, -320); \ -+ LD_64(a4, -384); \ -+ ST_64(a3, -384); \ -+ LD_64(a4, -448); \ -+ ST_64(a3, -448); \ -+ LD_64(a4, -512); \ -+ ST_64(a3, -512); \ -+ LD_64(a4, -576); \ -+ ST_64(a3, -576); \ -+ LD_64(a4, -640); \ -+ ST_64(a3, -640); \ -+ LD_64(a4, -704); \ -+ ST_64(a3, -704); \ -+ LD_64(a4, -768); \ -+ ST_64(a3, -768); \ -+ LD_64(a4, -832); \ -+ ST_64(a3, -832); \ -+ LD_64(a4, -896); \ -+ ST_64(a3, -896); \ -+ LD_64(a4, -960); \ -+ ST_64(a3, -960); \ -+ LD_64(a4, -1024); \ -+ ST_64(a3, -1024); -+ -+#ifdef ANDROID_CHANGES -+LEAF(MEMMOVE_NAME, 0) -+#else -+LEAF(MEMMOVE_NAME) -+#endif -+ -+//1st var: dest ptr: void *str1 $r4 a0 -+//2nd var: src ptr: void *str2 $r5 a1 -+//3rd var: size_t num -+//t0~t9 registers as temp -+ -+ add.d a4, a1, a2 -+ add.d a3, a0, a2 -+ beq a1, a0, less_1bytes -+ move t8, a0 -+ srai.d a6, a2, 4 #num/16 -+ beqz a6, less_16bytes #num<16 -+ srai.d a6, a2, 6 #num/64 -+ bnez a6, more_64bytes #num>64 -+ srai.d a6, a2, 5 -+ beqz a6, less_32bytes #num<32 -+ -+ ld.d t0, a1, 0 #32 -+#include -+#include -+#else -+#include -+#include -+#endif -+ -+#ifdef LOONGSON_TEST -+#define MEMSET _memset -+#else -+#define MEMSET memset -+#endif -+ -+#define ST_128(n) \ -+ st.d a1, a0, n; \ -+ st.d a1, a0, n+8 ; \ -+ st.d a1, a0, n+16 ; \ -+ st.d a1, a0, n+24 ; \ -+ st.d a1, a0, n+32 ; \ -+ st.d a1, a0, n+40 ; \ -+ st.d a1, a0, n+48 ; \ -+ st.d a1, a0, n+56 ; \ -+ st.d a1, a0, n+64 ; \ -+ st.d a1, a0, n+72 ; \ -+ st.d a1, a0, n+80 ; \ -+ st.d a1, a0, n+88 ; \ -+ st.d a1, a0, n+96 ; \ -+ st.d a1, a0, n+104; \ -+ st.d a1, a0, n+112; \ -+ st.d a1, a0, n+120; \ -+ -+//1st var: void *str $4 a0 -+//2nd var: int val $5 a1 -+//3rd var: size_t num $6 a2 -+ -+LEAF(MEMSET) -+ -+memset: -+ .align 6 -+ -+ bstrins.d a1, a1, 15, 8 -+ add.d t7, a0, a2 -+ bstrins.d a1, a1, 31, 16 -+ move t0, a0 -+ bstrins.d a1, a1, 63, 32 -+ srai.d t8, a2, 4 #num/16 -+ beqz t8, less_16bytes #num<16 -+ srai.d t8, a2, 6 #num/64 -+ bnez t8, more_64bytes #num>64 -+ srai.d t8, a2, 5 #num/32 -+ beqz t8, less_32bytes #num<32 -+ st.d a1, a0, 0 #32 -+#include -+#include -+ -+/* Short algorithm description: -+ * -+ * 1) if |x|==0: sin(x)=x, -+ * cos(x)=1. -+ * 2) if |x|<2^-27: sin(x)=x-x*DP_SMALL, raising underflow only when needed, -+ * cos(x)=1-|x|. -+ * 3) if |x|<2^-5 : sin(x)=x+x*x^2*DP_SIN2_0+x^5*DP_SIN2_1, -+ * cos(x)=1+1*x^2*DP_COS2_0+x^5*DP_COS2_1 -+ * 4) if |x|< Pi/4: sin(x)=x+x*x^2*(S0+x^2*(S1+x^2*(S2+x^2*(S3+x^2*S4)))), -+ * cos(x)=1+1*x^2*(C0+x^2*(C1+x^2*(C2+x^2*(C3+x^2*C4)))). -+ * 5) if |x| < 9*Pi/4: -+ * 5.1) Range reduction: -+ * k=trunc(|x|/(Pi/4)), j=(k+1)&0x0e, n=k+1, t=|x|-j*Pi/4. -+ * 5.2) Reconstruction: -+ * sign_sin = sign(x) * (-1.0)^(( n >>2)&1) -+ * sign_cos = (-1.0)^(((n+2)>>2)&1) -+ * poly_sin = ((((S4*t^2 + S3)*t^2 + S2)*t^2 + S1)*t^2 + S0)*t^2*t+t -+ * poly_cos = ((((C4*t^2 + C3)*t^2 + C2)*t^2 + C1)*t^2 + C0)*t^2*s+s -+ * if(n&2 != 0) { -+ * using cos(t) and sin(t) polynomials for |t|= 2^23, very large args: -+ * 7.1) Range reduction: -+ * k=trunc(|x|/(Pi/4)), j=(k+1)&0xfffffffe, n=k+1, t=|x|-j*Pi/4. -+ * 7.2) Reconstruction same as (5.2). -+ * 8) if x is Inf, return x-x, and set errno=EDOM. -+ * 9) if x is NaN, return x-x. -+ * -+ * Special cases: -+ * sin/cos(+-0) = +-0/1 not raising inexact/underflow, -+ * sin/cos(subnormal) raises inexact/underflow, -+ * sin/cos(min_normalized) raises inexact/underflow, -+ * sin/cos(normalized) raises inexact, -+ * sin/cos(Inf) = NaN, raises invalid, sets errno to EDOM, -+ * sin/cos(NaN) = NaN. -+ */ -+ -+#define COSF __cosf -+ -+#define LOADFD(rd, rs, label) \ -+ la.local rs, label;\ -+ fld.d rd, rs, 0 -+ -+#define LOADFS(rd, rs, label) \ -+ la.local rs, label;\ -+ fld.s rd, rs, 0 -+ -+#define FTOL(rd, rs, tmp) \ -+ ftintrz.l.d tmp, rs;\ -+ movfr2gr.d rd, tmp -+ -+#define FTOW(rd, rs, tmp) \ -+ ftintrz.w.d tmp, rs;\ -+ movfr2gr.s rd, tmp -+ -+#define WTOF(rd, rs, tmp) \ -+ movgr2fr.w tmp, rs;\ -+ ffint.d.w rd, tmp -+ -+#define LTOF(rd, rs, tmp) \ -+ movgr2fr.d tmp, rs;\ -+ ffint.d.l rd, tmp -+ -+LEAF(COSF) -+ .align 2 -+ .align 3 -+ /* fa0 is SP x; fa1 is DP x */ -+ movfr2gr.s t0, fa0 /* Bits of x */ -+ fcvt.d.s fa1, fa0 /* DP x */ -+ li.w t1, 0x7fffffff -+ and t0, t0, t1 /* |x| */ -+ li.w t1, 0x3f490fdb /* const Pi/4 */ -+ bltu t0, t1, L(arg_less_pio4) /* |x| < Pi/4 branch */ -+ li.w t1, 0x40e231d6 /* 9*Pi/4 */ -+ la.local t4, L(DP_) /*DP_ base addr*/ -+ bgeu t0, t1, L(greater_or_equal_9pio4) /* |x| >= 9*Pi/4 branch */ -+/* L(median_args): */ -+ /* Here if Pi/4<=|x|<9*Pi/4 */ -+ fabs.d fa0, fa1 /* DP |x| */ -+ fld.d fa1, t4, 56 /* 4/Pi */ -+ fmul.d fa1, fa1, fa0 /* DP |x|/(Pi/4) */ -+ FTOW( t0, fa1, fa1 ) /* k=trunc(|x|/(Pi/4)) */ -+ la.local t1, L(PIO2J) /* base addr of PIO2J table */ -+ addi.w t0, t0, 1 /* k+1 */ -+ bstrpick.d t2, t0, 3, 1 /* j=n/2 */ -+ alsl.d t1, t2, t1, 3 -+ fld.d fa1, t1, 0 /* j*Pi/2 */ -+ addi.w t0, t0, 2 /* n = k+3 */ -+ fsub.d fa0, fa0, fa1 /* t = |x| - j * Pi/2 */ -+/* Input: t0=n fa0=t*/ -+L(reduced): -+ /* Here if cos(x) calculated using cos(t) polynomial for |t|>2)&1) -+ * result = s * (1.0+t^2*(C0+t^2*(C1+t^2*(C2+t^2*(C3+t^2*C4))))) -+ -+ * Here if cos(x) calculated using sin(t) polynomial for |t|>2)&1) -+ * result = s * t * (1.0+t^2*(S0+t^2*(S1+t^2*(S2+t^2*(S3+t^2*S4))))) -+ */ -+ /* TODO: what is the best order ??? */ -+ /* load-to-use latency, hardware module usage, integer pipeline & float pipeline */ -+ /* cancel branch */ -+ slli.w t0, t0, 1 /* (n << 1) */ -+ andi t1, t0, 4 /* (n << 1) & 4 */ -+ alsl.d t2, t1, t4, 4 /* adjust to DP_C or DP_S */ -+ fld.d fa3, t2, 32 /* C4 */ -+ andi t0, t0, 8 /* =====> (n << 1) & 8 */ -+ fmul.d fa1, fa0, fa0 /* y=x^2 */ -+ fld.d fa4, t2, 16 /* C2 */ -+ fmul.d fa2, fa1, fa1 /* z=x^4 */ -+ fld.d fa5, t2, 24 /* C3 */ -+ la.local t3, L(DP_ONES) /* =====> DP_ONES */ -+ fld.d fa6, t2, 8 /* C1 */ -+ fmadd.d fa4, fa2, fa3, fa4 /* cx = C2+z*C4 */ -+ fld.d fa3, t2, 0 /* C0 */ -+ fmadd.d fa5, fa2, fa5, fa6 /* cy = C1+z*C3 */ -+ fld.d fa6, t3, 0 /* one */ -+ fmadd.d fa4, fa2, fa4, fa3 /* cx = C0+z*cx */ -+ add.d t0, t0, t3 /* =====> addr */ -+ fmadd.d fa4, fa1, fa5, fa4 /* cx = cx+y*cy */ -+ fld.d fa2, t0, 0 /* sign */ -+ fmadd.d fa4, fa4, fa1, fa6 /* 1.0+y*cx */ -+ fmul.d fa1, fa2, fa4 /* sign * cx */ -+ bnez t1, L_return -+ fmul.d fa1, fa1, fa0 /* t*s, where s = sign(x) * (-1.0)^((n>>2)&1) */ -+L_return: -+ fcvt.s.d fa0, fa1 /* SP result */ -+ jr ra -+ -+L(greater_or_equal_9pio4): -+ /* Here if |x|>=9*Pi/4 */ -+ li.w t1, 0x7f800000 /* x is Inf or NaN? */ -+ bgeu t0, t1, L(inf_or_nan) /* |x| >= Inf branch */ -+ /* Here if finite |x|>=9*Pi/4 */ -+ li.w t1, 0x4b000000 /* 2^23 */ -+ bgeu t0, t1, L(greater_or_equal_2p23) /* |x| >= 2^23 branch */ -+ /* Here if 9*Pi/4<=|x|<2^23 */ -+ fabs.d fa0, fa1 /* DP |x| */ -+ fld.d fa1, t4, 56 -+ fmul.d fa1, fa1, fa0 /* |x|/(Pi/4) */ -+ FTOW( t0, fa1, fa1 ) /* k=trunc(|x|/(Pi/4)) */ -+ addi.w t0, t0, 1 /* k+1 */ -+ srli.w t1, t0, 1 /* x=n/2 */ -+ WTOF( fa1, t1, fa1 ) /* DP x */ -+ fld.d fa2, t4, 104 /* -PIO2HI = high part of -Pi/2 */ -+ fld.d fa3, t4, 112 /* -PIO2LO = low part of -Pi/2 */ -+ fmadd.d fa0, fa2, fa1, fa0 /* |x| - x*PIO2HI */ -+ addi.w t0, t0, 2 /* n = k+3 */ -+ fmadd.d fa0, fa3, fa1, fa0 /* |x| - x*PIO2HI - x*PIO2LO */ -+ b L(reduced) -+ -+L(greater_or_equal_2p23): -+ /* Here if finite |x|>=2^23 */ -+ fabs.s fa5, fa0 /* SP |x| */ -+ /* bitpos = (ix>>23) - BIAS_32; */ -+ srli.w t0, t0, 23 /*TODO???srai.w eb = biased exponent of x */ -+ /* bitpos = eb - 0x7f + 59, where 0x7f is exponent bias */ -+ addi.w t0, t0, -124 /* t0 = bitpos */ -+ /* t3= j = bitpos/28 */ -+ /* x/28 = (x * ((0x100000000 / 28) + 1)) >> 32 */ -+ li.w t1, 0x924924a -+ mulh.wu t0, t1, t0 -+ fcvt.d.s fa5, fa5 /* Convert to double */ -+ /* TODO: what is the best order ??? */ -+ la.local t1, L(invpio4_table) /* t2 */ -+ alsl.d t1, t0, t1, 3 -+ fld.d fa0, t1, 0 /* invpio4_table[j] */ -+ fld.d fa1, t1, 8 /* invpio4_table[j+1] */ -+ fmul.d fa0, fa0, fa5 /* a = invpio4_table[j]*|x| */ -+ fld.d fa2, t1, 16 /* invpio4_table[j+2] */ -+ fmul.d fa1, fa1, fa5 /* b = invpio4_table[j+1]*|x| */ -+ fld.d fa3, t1, 24 /* invpio4_table[j+3] */ -+ fmul.d fa2, fa2, fa5 /* c = invpio4_table[j+2]*|x| */ -+ fmul.d fa3, fa3, fa5 /* d = invpio4_table[j+3]*|x| */ -+/*TODO: overflow check*/ -+ FTOL( t0, fa0, fa4 ) /*uint64_t l = a; TODO: change the order*/ -+ li.w t1, -8 /* 0xfffffffffffffff8 */ -+ and t0, t0, t1 /* l &= ~0x7; */ -+ LTOF( fa4, t0, fa4 ) /* DP l*/ -+ fsub.d fa0, fa0, fa4 /* a -= l; */ -+ fadd.d fa4, fa0, fa1 /* fa4 double e = a + b; */ -+/*TODO: overflow check*/ -+ FTOL( t0, fa4, fa4 ) /*uint64_t l = e;*/ -+ andi t2, t0, 1 /* l & 1 TODO: change the order*/ -+ LOADFD( fa5, t1, L(DP_ONES) ) /* fa5 = 1.0 */ -+ LTOF( fa4, t0, fa4 ) /* fa4 DP l*/ -+/* critical!!!! the order */ -+ fsub.d fa0, fa0, fa4 -+ fld.d fa4, t4, 120 /* PI_4 */ -+ beqz t2, L_even_integer -+/*L_odd_integer:*/ -+ fsub.d fa0, fa0, fa5 -+ fadd.d fa0, fa0, fa1 -+ fadd.d fa2, fa2, fa3 -+ fadd.d fa0, fa0, fa2 -+ addi.d t0, t0, 3 -+ fmul.d fa0, fa0, fa4 -+ b L(reduced) -+L_even_integer: -+ fadd.d fa0, fa0, fa1 -+ fadd.d fa2, fa2, fa3 -+ fadd.d fa0, fa0, fa2 -+ fcmp.sle.d $fcc0, fa0, fa5 -+ addi.d t0, t0, 3 -+ bcnez $fcc0, L_leq_one -+/*L_gt_one:*/ -+ fld.d fa2, t1, 16 /* 2.0 */ -+ addi.d t0, t0, 1 -+ fsub.d fa0, fa0, fa2 -+L_leq_one: -+ fmul.d fa0, fa0, fa4 -+ b L(reduced) -+ -+L(arg_less_pio4): -+ /* Here if |x| -+#include -+#include -+ -+/* Short algorithm description: -+ * -+ * 1) if |x|==0: sin(x)=x, -+ * cos(x)=1. -+ * 2) if |x|<2^-27: sin(x)=x-x*DP_SMALL, raising underflow only when needed, -+ * cos(x)=1-|x|. -+ * 3) if |x|<2^-5 : sin(x)=x+x*x^2*DP_SIN2_0+x^5*DP_SIN2_1, -+ * cos(x)=1+1*x^2*DP_COS2_0+x^5*DP_COS2_1 -+ * 4) if |x|< Pi/4: sin(x)=x+x*x^2*(S0+x^2*(S1+x^2*(S2+x^2*(S3+x^2*S4)))), -+ * cos(x)=1+1*x^2*(C0+x^2*(C1+x^2*(C2+x^2*(C3+x^2*C4)))). -+ * 5) if |x| < 9*Pi/4: -+ * 5.1) Range reduction: -+ * k=trunc(|x|/(Pi/4)), j=(k+1)&0x0e, n=k+1, t=|x|-j*Pi/4. -+ * 5.2) Reconstruction: -+ * sign_sin = sign(x) * (-1.0)^(( n >>2)&1) -+ * sign_cos = (-1.0)^(((n+2)>>2)&1) -+ * poly_sin = ((((S4*t^2 + S3)*t^2 + S2)*t^2 + S1)*t^2 + S0)*t^2*t+t -+ * poly_cos = ((((C4*t^2 + C3)*t^2 + C2)*t^2 + C1)*t^2 + C0)*t^2*s+s -+ * if(n&2 != 0) { -+ * using cos(t) and sin(t) polynomials for |t|= 2^23, very large args: -+ * 7.1) Range reduction: -+ * k=trunc(|x|/(Pi/4)), j=(k+1)&0xfffffffe, n=k+1, t=|x|-j*Pi/4. -+ * 7.2) Reconstruction same as (5.2). -+ * 8) if x is Inf, return x-x, and set errno=EDOM. -+ * 9) if x is NaN, return x-x. -+ * -+ * Special cases: -+ * sin/cos(+-0) = +-0/1 not raising inexact/underflow, -+ * sin/cos(subnormal) raises inexact/underflow, -+ * sin/cos(min_normalized) raises inexact/underflow, -+ * sin/cos(normalized) raises inexact, -+ * sin/cos(Inf) = NaN, raises invalid, sets errno to EDOM, -+ * sin/cos(NaN) = NaN. -+ */ -+ -+#define SINF __sinf -+ -+#define LOADFD(rd, rs, label) \ -+ la.local rs, label;\ -+ fld.d rd, rs, 0 -+ -+#define LOADFS(rd, rs, label) \ -+ la.local rs, label;\ -+ fld.s rd, rs, 0 -+ -+#define FTOL(rd, rs, tmp) \ -+ ftintrz.l.d tmp, rs;\ -+ movfr2gr.d rd, tmp -+ -+#define FTOW(rd, rs, tmp) \ -+ ftintrz.w.d tmp, rs;\ -+ movfr2gr.s rd, tmp -+ -+#define WTOF(rd, rs, tmp) \ -+ movgr2fr.w tmp, rs;\ -+ ffint.d.w rd, tmp -+ -+#define LTOF(rd, rs, tmp) \ -+ movgr2fr.d tmp, rs;\ -+ ffint.d.l rd, tmp -+ -+LEAF(SINF) -+ .align 2 -+ .align 3 -+ /* fa0 is SP x; fa1 is DP x */ -+ movfr2gr.s t2, fa0 /* Bits of x */ -+ fcvt.d.s fa1, fa0 /* DP x */ -+ li.w t1, 0x7fffffff -+ and t0, t2, t1 /* |x| */ -+ li.w t1, 0x3f490fdb /* const Pi/4 */ -+ bltu t0, t1, L(arg_less_pio4) /* |x| < Pi/4 branch */ -+ li.w t1, 0x40e231d6 /* 9*Pi/4 */ -+ la.local t4, L(DP_) /*DP_ base addr*/ -+ bstrpick.d t5, t2, 31, 31 /* sign of x */ -+ slli.w t5, t5, 3 -+ bgeu t0, t1, L(greater_or_equal_9pio4) /* |x| >= 9*Pi/4 branch */ -+/* L(median_args): */ -+ /* Here if Pi/4<=|x|<9*Pi/4 */ -+ fabs.d fa0, fa1 /* DP |x| */ -+ fld.d fa1, t4, 56 /* 4/Pi */ -+ fmul.d fa1, fa1, fa0 /* DP |x|/(Pi/4) */ -+ FTOW( t0, fa1, fa1 ) /* k=trunc(|x|/(Pi/4)) */ -+ la.local t1, L(PIO2J) /* base addr of PIO2J table */ -+ addi.w t0, t0, 1 /* k+1 */ -+ bstrpick.d t2, t0, 3, 1 /* j=n/2 */ -+ alsl.d t1, t2, t1, 3 -+ fld.d fa1, t1, 0 /* j*Pi/2 */ -+ fsub.d fa0, fa0, fa1 /* t = |x| - j * Pi/2 */ -+/* Input: t0=n fa0=t*/ -+/* Input: t0=n fa0=t, t5=sign(x) */ -+L(reduced): -+ /* Here if cos(x) calculated using cos(t) polynomial for |t|>2)&1) -+ * result = s * (1.0+t^2*(C0+t^2*(C1+t^2*(C2+t^2*(C3+t^2*C4))))) -+ -+ * Here if cos(x) calculated using sin(t) polynomial for |t|>2)&1) -+ * result = s * t * (1.0+t^2*(S0+t^2*(S1+t^2*(S2+t^2*(S3+t^2*S4))))) -+ */ -+ /* TODO: what is the best order ??? */ -+ /* load-to-use latency, hardware module usage, integer pipeline & float pipeline */ -+ /* cancel branch */ -+ slli.w t0, t0, 1 /* (n << 1) */ -+ andi t1, t0, 4 /* (n << 1) & 4 */ -+ alsl.d t2, t1, t4, 4 /* adjust to DP_C or DP_S */ -+ fld.d fa3, t2, 32 /* C4 */ -+ andi t0, t0, 8 /* =====> (n << 1) & 8 */ -+ fmul.d fa1, fa0, fa0 /* y=x^2 */ -+ xor t0, t0, t5 /* (-1.0)^((n>>2)&1) XOR sign(x) */ -+ fld.d fa4, t2, 16 /* C2 */ -+ fmul.d fa2, fa1, fa1 /* z=x^4 */ -+ fld.d fa5, t2, 24 /* C3 */ -+ la.local t3, L(DP_ONES) /* =====> DP_ONES */ -+ fld.d fa6, t2, 8 /* C1 */ -+ fmadd.d fa4, fa2, fa3, fa4 /* cx = C2+z*C4 */ -+ fld.d fa3, t2, 0 /* C0 */ -+ fmadd.d fa5, fa2, fa5, fa6 /* cy = C1+z*C3 */ -+ fld.d fa6, t3, 0 /* 1.0 */ -+ fmadd.d fa4, fa2, fa4, fa3 /* cx = C0+z*cx */ -+ add.d t0, t0, t3 /* =====> addr */ -+ fmadd.d fa4, fa1, fa5, fa4 /* cx = cx+y*cy */ -+ fld.d fa2, t0, 0 /* sign */ -+ fmadd.d fa4, fa4, fa1, fa6 /* 1.0+y*cx */ -+ fmul.d fa1, fa2, fa4 /* sign * cx */ -+ bnez t1, L_return -+ fmul.d fa1, fa1, fa0 /* t*s, where s = sign(x) * (-1.0)^((n>>2)&1) */ -+L_return: -+ fcvt.s.d fa0, fa1 /* SP result */ -+ jr ra -+ -+L(greater_or_equal_9pio4): -+ /* Here if |x|>=9*Pi/4 */ -+ li.w t1, 0x7f800000 /* x is Inf or NaN? */ -+ bgeu t0, t1, L(inf_or_nan) /* |x| >= Inf branch */ -+ /* Here if finite |x|>=9*Pi/4 */ -+ li.w t1, 0x4b000000 /* 2^23 */ -+ bgeu t0, t1, L(greater_or_equal_2p23) /* |x| >= 2^23 branch */ -+ /* Here if 9*Pi/4<=|x|<2^23 */ -+ fabs.d fa0, fa1 /* DP |x| */ -+ fld.d fa1, t4, 56 -+ fmul.d fa1, fa1, fa0 /* |x|/(Pi/4) */ -+ FTOW( t0, fa1, fa1 ) /* k=trunc(|x|/(Pi/4)) */ -+ addi.w t0, t0, 1 /* k+1 */ -+ srli.w t1, t0, 1 /* x=n/2 */ -+ WTOF( fa1, t1, fa1 ) /* DP x */ -+ fld.d fa2, t4, 104 /* -PIO2HI = high part of -Pi/2 */ -+ fld.d fa3, t4, 112 /* -PIO2LO = low part of -Pi/2 */ -+ fmadd.d fa0, fa2, fa1, fa0 /* |x| - x*PIO2HI */ -+ fmadd.d fa0, fa3, fa1, fa0 /* |x| - x*PIO2HI - x*PIO2LO */ -+ b L(reduced) -+ -+L(greater_or_equal_2p23): -+ /* Here if finite |x|>=2^23 */ -+ fabs.s fa5, fa0 /* SP |x| */ -+ /* bitpos = (ix>>23) - BIAS_32; */ -+ srli.w t0, t0, 23 /*TODO???srai.w eb = biased exponent of x */ -+ /* bitpos = eb - 0x7f + 59, where 0x7f is exponent bias */ -+ addi.w t0, t0, -124 /* t0 = bitpos */ -+ /* t3= j = bitpos/28 */ -+ /* x/28 = (x * ((0x100000000 / 28) + 1)) >> 32 */ -+ li.w t1, 0x924924a -+ mulh.wu t0, t1, t0 -+ fcvt.d.s fa5, fa5 /* Convert to double */ -+ /* TODO: what is the best order ??? */ -+ la.local t1, L(invpio4_table) /* t2 */ -+ alsl.d t1, t0, t1, 3 -+ fld.d fa0, t1, 0 /* invpio4_table[j] */ -+ fld.d fa1, t1, 8 /* invpio4_table[j+1] */ -+ fmul.d fa0, fa0, fa5 /* a = invpio4_table[j]*|x| */ -+ fld.d fa2, t1, 16 /* invpio4_table[j+2] */ -+ fmul.d fa1, fa1, fa5 /* b = invpio4_table[j+1]*|x| */ -+ fld.d fa3, t1, 24 /* invpio4_table[j+3] */ -+ fmul.d fa2, fa2, fa5 /* c = invpio4_table[j+2]*|x| */ -+ fmul.d fa3, fa3, fa5 /* d = invpio4_table[j+3]*|x| */ -+/*TODO: overflow check*/ -+ FTOL( t0, fa0, fa4 ) /*uint64_t l = a; TODO: change the order*/ -+ li.w t1, -8 /* 0xfffffffffffffff8 */ -+ and t0, t0, t1 /* l &= ~0x7; */ -+ LTOF( fa4, t0, fa4 ) /* DP l*/ -+ fsub.d fa0, fa0, fa4 /* a -= l; */ -+ fadd.d fa4, fa0, fa1 /* fa4 double e = a + b; */ -+/*TODO: overflow check*/ -+ FTOL( t0, fa4, fa4 ) /*uint64_t l = e;*/ -+ andi t2, t0, 1 /* l & 1 TODO: change the order*/ -+ LOADFD( fa5, t1, L(DP_ONES) ) /* fa5 = 1.0 */ -+ LTOF( fa4, t0, fa4 ) /* fa4 DP l*/ -+/* critical!!!! the order */ -+ fsub.d fa0, fa0, fa4 -+ fld.d fa4, t4, 120 /* PI_4 */ -+ beqz t2, L_even_integer -+/*L_odd_integer:*/ -+ fsub.d fa0, fa0, fa5 -+ fadd.d fa0, fa0, fa1 -+ fadd.d fa2, fa2, fa3 -+ fadd.d fa0, fa0, fa2 -+ addi.d t0, t0, 1 -+ fmul.d fa0, fa0, fa4 -+ b L(reduced) -+L_even_integer: -+ fadd.d fa0, fa0, fa1 -+ fadd.d fa2, fa2, fa3 -+ fadd.d fa0, fa0, fa2 -+ fcmp.sle.d $fcc0, fa0, fa5 -+ addi.d t0, t0, 1 -+ bcnez $fcc0, L_leq_one -+/*L_gt_one:*/ -+ fld.d fa2, t1, 16 /* 2.0 */ -+ addi.d t0, t0, 1 -+ fsub.d fa0, fa0, fa2 -+L_leq_one: -+ fmul.d fa0, fa0, fa4 -+ b L(reduced) -+ -+L(arg_less_pio4): -+ /* Here if |x| -+#include -+ -+ -+ -+ -+ -+#define L_ADDIU addi.d -+#define L_ADDU add.d -+#define L_SUBU sub.d -+ -+#define STRCHR strchr -+#define MOVN(rd,rs,rt) \ -+ maskeqz t6, rs, rt;\ -+ masknez rd, rd, rt;\ -+ or rd, rd, t6 -+ -+#define MOVN2(rd,rt) \ -+ masknez rd, rd, rt;\ -+ or rd, rd, rt -+ -+ -+/* char * strchr (const char *s1, int c); */ -+ -+LEAF(STRCHR) -+ .align 6 -+ -+ li.w t4, 0x7 -+ lu12i.w a2, 0x01010 -+ bstrins.d a1, a1, 15, 8 -+ andi t0, a0, 0x7 -+ -+ ori a2, a2, 0x101 -+ andn t4, a0, t4 -+ slli.w t1, t0, 3 -+ -+ ld.d t4, t4, 0 -+ -+ -+ nor t8, zero, zero -+ bstrins.d a1, a1, 31, 16 -+ srl.d t4, t4, t1 -+ -+ bstrins.d a1, a1, 63, 32 -+ bstrins.d a2, a2, 63, 32 -+ srl.d a7, t8, t1 -+ -+ li.w t1, 8 -+ nor t8, a7, zero -+ slli.d a3, a2, 7 -+ or t5, t8, t4 -+ and t3, a7, a1 -+ -+ sub.w t1, t1, t0 -+ nor a3, a3, zero -+ xor t2, t5, t3 -+ sub.d a7, t5, a2 -+ nor a6, t5, a3 -+ -+ sub.d a5, t2, a2 -+ nor a4, t2, a3 -+ -+ and a6, a7, a6 -+ and a5, a5, a4 -+ or a7, a6, a5 -+ bnez a7, L(_mc8_a) -+ -+ L_ADDU a0, a0, t1 -+L(_aloop): -+ ld.d t4, a0, 0 -+ -+ xor t2, t4, a1 -+ sub.d a7, t4, a2 -+ nor a6, t4, a3 -+ sub.d a5, t2, a2 -+ -+ nor a4, t2, a3 -+ and a6, a7, a6 -+ and a5, a5, a4 -+ or a7, a6, a5 -+ bnez a7, L(_mc8_a) -+ -+ ld.d t4, a0, 8 -+ L_ADDIU a0, a0, 16 -+ xor t2, t4, a1 -+ sub.d a7, t4, a2 -+ nor a6, t4, a3 -+ sub.d a5, t2, a2 -+ -+ nor a4, t2, a3 -+ and a6, a7, a6 -+ and a5, a5, a4 -+ or a7, a6, a5 -+ beqz a7, L(_aloop) -+ -+ L_ADDIU a0, a0, -8 -+L(_mc8_a): -+ -+ ctz.d t0, a5 -+ ctz.d t2, a6 -+ -+ srli.w t0, t0, 3 -+ srli.w t2, t2, 3 -+ sltu t1, t2, t0 -+ L_ADDU v0, a0, t0 -+ masknez v0, v0, t1 -+ jr ra -+END(STRCHR) -+ -+#ifndef ANDROID_CHANGES -+#ifdef _LIBC -+libc_hidden_builtin_def (strchr) -+weak_alias (strchr, index) -+#endif -+#endif -diff --git a/sysdeps/loongarch/lp64/strchrnul.S b/sysdeps/loongarch/lp64/strchrnul.S -new file mode 100644 -index 00000000..a57a5065 ---- /dev/null -+++ b/sysdeps/loongarch/lp64/strchrnul.S -@@ -0,0 +1,156 @@ -+/* Copyright 2016 Loongson Technology Corporation Limited */ -+ -+/* Author: Songyuekun songyuekun@loongson.cn */ -+ -+/* -+ * ISA: MIPS64R2 -+ * ABI: N64 -+ */ -+ -+/* basic algorithm : -+ -+ +. use ld.d and mask for the first 8 bytes or less; -+ -+ +. build a1 with 8c with dins; -+ -+ +. use xor from a1 and v0 to check if is found; -+ -+ +. if (v0 - 0x0101010101010101) & (~(v0 | 0x7f7f7f7f7f7f7f7f)!= 0, v0 has -+ one byte is \0, else has no \0 -+ -+*/ -+ -+ -+ -+ -+#include -+#include -+ -+ -+ -+ -+ -+#define L_ADDIU addi.d -+#define L_ADDU add.d -+#define L_SUBU sub.d -+ -+#define STRCHRNUL __strchrnul -+ -+#define MOVN(rd,rs,rt) \ -+ maskeqz t6, rs, rt;\ -+ masknez rd, rd, rt;\ -+ or rd, rd, t6 -+ -+#define MOVZ(rd,rs,rt) \ -+ masknez t6, rs, rt;\ -+ maskeqz rd, rd, rt;\ -+ or rd, rd, t6 -+ -+ -+#define MOVN2(rd,rt) \ -+ masknez rd, rd, rt;\ -+ or rd, rd, rt -+ -+ -+/* char * strchrnul (const char *s1, int c); */ -+ -+LEAF(STRCHRNUL) -+ .align 6 -+ -+ li.w t4, 0x7 -+ lu12i.w a2, 0x01010 -+ bstrins.d a1, a1, 15, 8 -+ andi t0, a0, 0x7 -+ -+ ori a2, a2, 0x101 -+ andn t4, a0, t4 -+ slli.w t1, t0, 3 -+/* -+ ldr t4, 0(a0) -+*/ -+ ld.d t4, t4, 0 -+ -+ -+ nor t8, zero, zero -+ bstrins.d a1, a1, 31, 16 -+ srl.d t4, t4, t1 -+ -+ preld 0, a0, 32 -+ bstrins.d a1, a1, 63, 32 -+ bstrins.d a2, a2, 63, 32 -+ srl.d a7, t8, t1 -+ -+ nor t8, a7, zero -+ slli.d a3, a2, 7 -+ or t5, t8, t4 -+ and t3, a7, a1 -+ -+ nor a3, a3, zero -+ xor t2, t5, t3 -+ sub.d a7, t5, a2 -+ nor a6, t5, a3 -+ -+ li.w t1, 8 -+ sub.d a5, t2, a2 -+ nor a4, t2, a3 -+ -+ and a6, a7, a6 -+ and a5, a5, a4 -+ or a7, a6, a5 -+ bnez a7, L(_mc8_a) -+ -+ -+ sub.w t1, t1, t0 -+ L_ADDU a0, a0, t1 -+L(_aloop): -+ ld.d t4, a0, 0 -+ -+ xor t2, t4, a1 -+ sub.d a7, t4, a2 -+ nor a6, t4, a3 -+ sub.d a5, t2, a2 -+ -+ nor a4, t2, a3 -+ and a6, a7, a6 -+ and a5, a5, a4 -+ -+ or a7, a6, a5 -+ bnez a7, L(_mc8_a) -+ -+ ld.d t4, a0, 8 -+ L_ADDIU a0, a0, 16 -+ -+ xor t2, t4, a1 -+ sub.d a7, t4, a2 -+ nor a6, t4, a3 -+ sub.d a5, t2, a2 -+ -+ nor a4, t2, a3 -+ and a6, a7, a6 -+ and a5, a5, a4 -+ -+ or a7, a6, a5 -+ beqz a7, L(_aloop) -+ -+ L_ADDIU a0, a0, -8 -+L(_mc8_a): -+ -+ ctz.d t0, a5 -+ ctz.d t2, a6 -+ -+ srli.w t0, t0, 3 -+ srli.w t2, t2, 3 -+ slt t1, t0, t2 -+ -+ MOVZ(t0,t2,t1) -+ -+ L_ADDU v0, a0, t0 -+ jr ra -+END(STRCHRNUL) -+ -+#ifndef ANDROID_CHANGES -+#ifdef _LIBC -+weak_alias(__strchrnul, strchrnul) -+libc_hidden_builtin_def (__strchrnul) -+#endif -+#endif -diff --git a/sysdeps/loongarch/lp64/strcmp.S b/sysdeps/loongarch/lp64/strcmp.S -new file mode 100644 -index 00000000..11474bf2 ---- /dev/null -+++ b/sysdeps/loongarch/lp64/strcmp.S -@@ -0,0 +1,197 @@ -+/* Copyright 2016 Loongson Technology Corporation Limited */ -+ -+/* Author: songyuekun songyuekun@loongson.cn */ -+ -+/* -+ * ISA: MIPS64R2 -+ * ABI: N64 -+ */ -+ -+/* basic algorithm : -+ -+ +. let t0, t1 point to a0, a1, if a0 has smaller low 3 bit of a0 and a1, -+ set a4 to 1 and let t0 point to the larger of lower 3bit of a0 and a1 -+ -+ +. if low 3 bit of a0 equal low 3 bit of a0, use a ldr one time and more ld other times; -+ -+ +. if not, load partial t2 and t3, check if t2 has \0; -+ -+ +. then use use ld for t0, ldr for t1, -+ -+ +. if partial 8 byte from t1 has \0, compare partial 8 byte from t1 with 8 -+ byte from t0 with a mask in a7 -+ -+ +. if not, ldl other part of t1, compare 8 byte from t1 with 8 byte from t0 -+ -+ +. if (v0 - 0x0101010101010101) & (~v0) & 0x8080808080808080 != 0, v0 has -+ one byte is \0, else has no \0 -+ -+ +. for partial 8 byte from ldr t3, 0(a0), preload t3 with 0xffffffffffffffff -+ -+ -+*/ -+#include -+#include -+ -+ -+#define STRCMP strcmp -+ -+#define REP8_01 0x0101010101010101 -+#define REP8_7f 0x7f7f7f7f7f7f7f7f -+#define REP8_80 0x8080808080808080 -+ -+/* Parameters and Results */ -+#define src1 a0 -+#define src2 a1 -+#define result v0 -+// Note: v0 = a0 in N64 ABI -+ -+ -+/* Internal variable */ -+#define data1 t0 -+#define data2 t1 -+#define has_nul t2 -+#define diff t3 -+#define syndrome t4 -+#define zeroones t5 -+#define sevenf t6 -+#define pos t7 -+#define exchange t8 -+#define tmp1 a4 -+#define tmp2 a5 -+#define tmp3 a6 -+#define src1_off a2 -+#define src2_off a3 -+#define tmp4 a7 -+ -+/* rd <- if rc then ra else rb -+ will destroy tmp3 -+*/ -+#define CONDITIONSEL(rd,rc,ra,rb)\ -+ masknez tmp3, rb, rc;\ -+ maskeqz rd, ra, rc;\ -+ or rd, rd, tmp3 -+ -+ -+ -+/* int strcmp (const char *s1, const char *s2); */ -+ -+LEAF(STRCMP) -+ .align 4 -+ -+ xor tmp1, src1, src2 -+ lu12i.w zeroones, 0x01010 -+ lu12i.w sevenf, 0x7f7f7 -+ andi src1_off, src1, 0x7 -+ ori zeroones, zeroones, 0x101 -+ ori sevenf, sevenf, 0xf7f -+ andi tmp1, tmp1, 0x7 -+ bstrins.d zeroones, zeroones, 63, 32 -+ bstrins.d sevenf, sevenf, 63, 32 -+ bnez tmp1, strcmp_misaligned8 -+ bnez src1_off, strcmp_mutual_align -+strcmp_loop_aligned: -+ ld.d data1, src1, 0 -+ addi.d src1, src1, 8 -+ ld.d data2, src2, 0 -+ addi.d src2, src2, 8 -+strcmp_start_realigned: -+ sub.d tmp1, data1, zeroones -+ or tmp2, data1, sevenf -+ xor diff, data1, data2 -+ andn has_nul, tmp1, tmp2 -+ or syndrome, diff, has_nul -+ beqz syndrome, strcmp_loop_aligned -+ -+strcmp_end: -+ ctz.d pos, syndrome -+ bstrins.d pos, zero, 2, 0 -+ srl.d data1, data1, pos -+ srl.d data2, data2, pos -+ andi data1, data1, 0xff -+ andi data2, data2, 0xff -+ sub.d result, data1, data2 -+ jr ra -+strcmp_mutual_align: -+ bstrins.d src1, zero, 2, 0 -+ bstrins.d src2, zero, 2, 0 -+ slli.d tmp1, src1_off, 0x3 -+ ld.d data1, src1, 0 -+ sub.d tmp1, zero, tmp1 -+ ld.d data2, src2, 0 -+ addi.d src1, src1, 8 -+ addi.d src2, src2, 8 -+ nor tmp2, zero, zero -+ srl.d tmp2, tmp2, tmp1 -+ or data1, data1, tmp2 -+ or data2, data2, tmp2 -+ b strcmp_start_realigned -+ -+strcmp_misaligned8: -+ -+/* check -+ if ((src1 != 0) && ((src2 == 0 ) || (src1 < src2))) -+ then exchange(src1,src2) -+ -+*/ -+ andi src2_off, src2, 0x7 -+ slt tmp2, src1_off, src2_off -+ CONDITIONSEL(tmp2,src2_off,tmp2,tmp1) -+ maskeqz exchange, tmp2, src1_off -+ xor tmp3, src1, src2 -+ maskeqz tmp3, tmp3, exchange -+ xor src1, src1, tmp3 -+ xor src2, src2, tmp3 -+ -+ andi src1_off, src1, 0x7 -+ beqz src1_off, strcmp_loop_misaligned -+strcmp_do_misaligned: -+ ld.bu data1, src1, 0 -+ ld.bu data2, src2, 0 -+ xor tmp3, data1, data2 -+ addi.d src1, src1, 1 -+ masknez tmp3, data1, tmp3 -+ addi.d src2, src2, 1 -+ beqz tmp3, strcmp_done -+ andi src1_off, src1, 0x7 -+ bnez src1_off, strcmp_do_misaligned -+ -+strcmp_loop_misaligned: -+ andi tmp1, src2, 0xff8 -+ xori tmp1, tmp1, 0xff8 -+ beqz tmp1, strcmp_do_misaligned -+ ld.d data1, src1, 0 -+ ld.d data2, src2, 0 -+ addi.d src1, src1, 8 -+ addi.d src2, src2, 8 -+ -+ sub.d tmp1, data1, zeroones -+ or tmp2, data1, sevenf -+ xor diff, data1, data2 -+ andn has_nul, tmp1, tmp2 -+ or syndrome, diff, has_nul -+ beqz syndrome, strcmp_loop_misaligned -+// b strcmp_end -+strcmp_misalign_end: -+ ctz.d pos, syndrome -+ bstrins.d pos, zero, 2, 0 -+ srl.d data1, data1, pos -+ srl.d data2, data2, pos -+ andi data1, data1, 0xff -+ andi data2, data2, 0xff -+ sub.d tmp1, data1, data2 -+ sub.d tmp2, data2, data1 -+ CONDITIONSEL(result,exchange,tmp2,tmp1) -+ jr ra -+ -+strcmp_done: -+ sub.d tmp1, data1, data2 -+ sub.d tmp2, data2, data1 -+ CONDITIONSEL(result,exchange,tmp2,tmp1) -+ jr ra -+END(STRCMP) -+#ifndef ANDROID_CHANGES -+#ifdef _LIBC -+libc_hidden_builtin_def (strcmp) -+#endif -+#endif -diff --git a/sysdeps/loongarch/lp64/strcpy.S b/sysdeps/loongarch/lp64/strcpy.S -new file mode 100644 -index 00000000..ce39e5a1 ---- /dev/null -+++ b/sysdeps/loongarch/lp64/strcpy.S -@@ -0,0 +1,210 @@ -+/* Copyright 2016 Loongson Technology Corporation Limited */ -+ -+/* Author: Huang Pei huangpei@loongson.cn */ -+ -+/* -+ * ISA: MIPS64R2 -+ * ABI: N64 -+ */ -+ -+/* basic algorithm : -+ -+ +. if src aligned. just do the copy loop. if not, do the cross page check and copy one double word. -+ -+ Then move src to aligned. -+ -+ +. if (v0 - 0x0101010101010101) & (~v0) & 0x8080808080808080 != 0, v0 has -+ one byte is \0, else has no \0 -+ -+ -+*/ -+ -+ -+#include -+#include -+ -+ -+#define STRCPY strcpy -+ -+ -+#define REP8_01 0x0101010101010101 -+#define REP8_7f 0x7f7f7f7f7f7f7f7f -+#define REP8_80 0x8080808080808080 -+ -+/* Parameters and Results */ -+#define dest a0 -+#define src a1 -+#define result v0 -+// Note: v0 = a0 in N64 ABI -+ -+ -+/* Internal variable */ -+#define data t0 -+#define data1 t1 -+#define has_nul t2 -+#define diff t3 -+#define syndrome t4 -+#define zeroones t5 -+#define sevenf t6 -+#define pos t7 -+#define dest_backup t8 -+#define tmp1 a4 -+#define tmp2 a5 -+#define tmp3 a6 -+#define dest_off a2 -+#define src_off a3 -+#define tmp4 a7 -+ -+/* rd <- if rc then ra else rb -+ will destroy tmp3 -+*/ -+#define CONDITIONSEL(rd,rc,ra,rb)\ -+ masknez tmp3, rb, rc;\ -+ maskeqz rd, ra, rc;\ -+ or rd, rd, tmp3 -+ -+ -+ -+/* int strcpy (const char *s1, const char *s2); */ -+ -+LEAF(STRCPY) -+ .align 4 -+ -+ move dest_backup, dest -+ lu12i.w zeroones, 0x01010 -+ lu12i.w sevenf, 0x7f7f7 -+ ori zeroones, zeroones, 0x101 -+ ori sevenf, sevenf, 0xf7f -+ bstrins.d zeroones, zeroones, 63, 32 -+ bstrins.d sevenf, sevenf, 63, 32 -+ andi src_off, src, 0x7 -+ beqz src_off, strcpy_loop_aligned_1 -+ b strcpy_mutual_align -+strcpy_loop_aligned: -+ st.d data, dest, 0 -+ addi.d dest, dest, 8 -+strcpy_loop_aligned_1: -+ ld.d data, src, 0 -+ addi.d src, src, 8 -+strcpy_start_realigned: -+ sub.d tmp1, data, zeroones -+ or tmp2, data, sevenf -+ andn has_nul, tmp1, tmp2 -+ beqz has_nul, strcpy_loop_aligned -+ -+strcpy_end: -+ -+/* -+8 4 2 1 -+*/ -+ ctz.d pos, has_nul -+ srli.d pos, pos, 3 -+ addi.d pos, pos, 1 -+/* -+ Do 8/4/2/1 strcpy based on pos value. -+ pos value is the number of bytes to be copied -+ the bytes include the final \0 so the max length is 8 and the min length is 1 -+*/ -+ -+strcpy_end_8: -+ andi tmp1, pos, 0x8 -+ beqz tmp1, strcpy_end_4 -+ st.d data, dest, 0 -+ move dest, dest_backup -+ jr ra -+strcpy_end_4: -+ andi tmp1, pos, 0x4 -+ beqz tmp1, strcpy_end_2 -+ st.w data, dest, 0 -+ srli.d data, data, 32 -+ addi.d dest, dest, 4 -+strcpy_end_2: -+ andi tmp1, pos, 0x2 -+ beqz tmp1, strcpy_end_1 -+ st.h data, dest, 0 -+ srli.d data, data, 16 -+ addi.d dest, dest, 2 -+strcpy_end_1: -+ andi tmp1, pos, 0x1 -+ beqz tmp1, strcpy_end_ret -+ st.b data, dest, 0 -+strcpy_end_ret: -+ move result, dest_backup -+ jr ra -+ -+ -+strcpy_mutual_align: -+/* -+ Check if around src page bound. -+ if not go to page cross ok. -+ if it is, do further check. -+ use tmp2 to accelerate. -+*/ -+ -+ li.w tmp2, 0xff8 -+ andi tmp1, src, 0xff8 -+ beq tmp1, tmp2, strcpy_page_cross -+ -+strcpy_page_cross_ok: -+/* -+ Load a misaligned double word and check if has \0 -+ If no, do a misaligned double word paste. -+ If yes, calculate the number of avaliable bytes, -+ then jump to 4/2/1 end. -+*/ -+ ld.d data, src, 0 -+ sub.d tmp1, data, zeroones -+ or tmp2, data, sevenf -+ andn has_nul, tmp1, tmp2 -+ bnez has_nul, strcpy_end -+strcpy_mutual_align_finish: -+/* -+ Before jump back to align loop, make dest/src aligned. -+ This will cause a duplicated paste for several bytes between the first double word and the second double word, -+ but should not bring a problem. -+*/ -+ li.w tmp1, 8 -+ st.d data, dest, 0 -+ sub.d tmp1, tmp1, src_off -+ add.d src, src, tmp1 -+ add.d dest, dest, tmp1 -+ -+ b strcpy_loop_aligned_1 -+ -+strcpy_page_cross: -+/* -+ ld.d from aligned address(src & ~0x7). -+ check if high bytes have \0. -+ it not, go back to page cross ok, -+ since the string is supposed to cross the page bound in such situation. -+ if it is, do a srl for data to make it seems like a direct double word from src, -+ then go to 4/2/1 strcpy end. -+ -+ tmp4 is 0xffff...ffff mask -+ tmp2 demonstrate the bytes to be masked -+ tmp2 = src_off << 3 -+ data = data >> (src_off * 8) | -1 << (64 - src_off * 8) -+ and -+ -1 << (64 - src_off * 8) -> ~(-1 >> (src_off * 8)) -+ -+*/ -+ li.w tmp1, 0x7 -+ andn tmp3, src, tmp1 -+ ld.d data, tmp3, 0 -+ li.w tmp4, -1 -+ slli.d tmp2, src_off, 3 -+ srl.d tmp4, tmp4, tmp2 -+ srl.d data, data, tmp2 -+ nor tmp4, tmp4, zero -+ or data, data, tmp4 -+ sub.d tmp1, data, zeroones -+ or tmp2, data, sevenf -+ andn has_nul, tmp1, tmp2 -+ beqz has_nul, strcpy_page_cross_ok -+ b strcpy_end -+END(STRCPY) -+#ifndef ANDROID_CHANGES -+#ifdef _LIBC -+libc_hidden_builtin_def (strcpy) -+#endif -+#endif -diff --git a/sysdeps/loongarch/lp64/strlen.S b/sysdeps/loongarch/lp64/strlen.S -new file mode 100644 -index 00000000..a34d8b69 ---- /dev/null -+++ b/sysdeps/loongarch/lp64/strlen.S -@@ -0,0 +1,135 @@ -+/* Copyright 2016 Loongson Technology Corporation Limited */ -+ -+/* Author: Songyuekun songyuekun@loongson.cn */ -+ -+/* -+ * ISA: MIPS64R2 -+ * ABI: N64 -+ */ -+/* -+algorithm: -+ -+ #. use ld/ldr to access word/partial word in the string -+ -+ #. use (x - 0x0101010101010101) & (~(x | 0x7f7f7f7f7f7f7f7f) != 0 to -+ judge if x has zero byte -+ -+ #. use dctz((x - 0x0101010101010101) & (~(x | 0x7f7f7f7f7f7f7f7f) >> 3 -+ to get the index of first rightmost zero byte in dword x; -+ -+ #. use dctz(x) = 64 - dclz(~x & (x-1)); -+ -+ #. use pointer to the last non zero byte minus pointer to the start -+ of the string to get the length of string -+ -+*/ -+ -+ -+#include -+#include -+ -+ -+ -+#define L_ADDIU addi.d -+#define L_ADDU add.d -+#define L_SUBU sub.d -+ -+#define STRLEN strlen -+#define L(x) x -+ -+ -+/* size_t strlen (const char *s1); */ -+ -+ .text; -+ .globl strlen; -+ .align 5; -+ cfi_startproc ; -+ .type strlen, @function; -+strlen: -+ -+ //LEAF(strlen) -+ #preld 0, a0, 0 -+ -+ nor t4, zero, zero -+ lu12i.w a2, 0x01010 -+ andi t5, a0, 0x7 -+ -+ li.w t7, 0x7 -+ slli.d t6, t5, 0x3 -+ andn t7, a0, t7 -+ ld.d a1, t7, 0 -+ sub.d t7, zero, t6 -+ sll.d t4, t4, t7 -+ maskeqz t4, t4, t6 -+ srl.d a1, a1, t6 -+ or a1, a1, t4 -+ -+ -+ ori a2, a2, 0x101 -+ nor t1, a1, zero -+ li.w a4, 8 -+ -+ #preld 0, a0, 32 -+ bstrins.d a2, a2, 63, 32 -+ sub.d a5, a4, t5 -+ move t5, a0 -+ -+ sub.d t0, a1, a2 -+ slli.d t4, a2, 7 -+ nor a3, zero, t4 -+ nor t1, a1, a3 -+ -+ and t0, t0, t1 -+ #preld 0, a0, 64 -+ bnez t0, strlen_count1 /* instead of use bnel with daddu a0, a0, a5 in branch slot */ -+ L_ADDU a0, a0, a5 -+strlen_loop: -+ ld.d a1, a0, 0 -+ sub.d t0, a1, a2 -+ and t1, t0, t4 -+ bnez t1, strlen_count_pre -+ ld.d a1, a0, 8 -+ sub.d t0, a1, a2 -+ and t1, t0, t4 -+ L_ADDIU a0, a0, 16 -+ beqz t1, strlen_loop -+strlen_count: -+ addi.d a0, a0, -8 -+strlen_count_pre: -+ nor t1, a1, a3 -+ and t0, t0, t1 -+ beqz t0, strlen_noascii_start -+strlen_count1: -+ ctz.d t1, t0 -+ L_SUBU v0, a0, t5 -+ srli.w t1, t1, 3 -+ L_ADDU v0, v0, t1 -+ jr ra -+strlen_noascii_start: -+ addi.d a0, a0, 8 -+strlen_loop_noascii: -+ ld.d a1, a0, 0 -+ sub.d t0, a1, a2 -+ nor t1, a1, a3 -+ and t0, t0, t1 -+ bnez t0, strlen_count1 -+ ld.d a1, a0, 8 -+ sub.d t0, a1, a2 -+ nor t1, a1, a3 -+ and t0, t0, t1 -+ L_ADDIU a0, a0, 16 -+ beqz t0, strlen_loop_noascii -+ addi.d a0, a0, -8 -+ ctz.d t1, t0 -+ L_SUBU v0, a0, t5 -+ srli.w t1, t1, 3 -+ L_ADDU v0, v0, t1 -+ jr ra -+END(STRLEN) -+ -+#ifndef ANDROID_CHANGES -+#ifdef _LIBC -+libc_hidden_builtin_def (strlen) -+#endif -+#endif -+ -diff --git a/sysdeps/loongarch/lp64/strncmp.S b/sysdeps/loongarch/lp64/strncmp.S -new file mode 100644 -index 00000000..29cc7b02 ---- /dev/null -+++ b/sysdeps/loongarch/lp64/strncmp.S -@@ -0,0 +1,269 @@ -+/* Copyright 2016 Loongson Technology Corporation Limited */ -+ -+/* Author: songyuekun songyuekun@loongson.cn */ -+ -+/* -+ * ISA: MIPS64R2 -+ * ABI: N64 -+ */ -+ -+/* basic algorithm : -+ -+ +. let t0, t1 point to a0, a1, if a0 has smaller low 3 bit of a0 and a1, -+ set a4 to 1 and let t0 point to the larger of lower 3bit of a0 and a1 -+ -+ +. if low 3 bit of a0 equal low 3 bit of a0, use a ldr one time and more ld other times; -+ -+ +. if not, load partial t2 and t3, check if t2 has \0; -+ -+ +. then use use ld for t0, ldr for t1, -+ -+ +. if partial 8 byte from t1 has \0, compare partial 8 byte from t1 with 8 -+ byte from t0 with a mask in a7 -+ -+ +. if not, ldl other part of t1, compare 8 byte from t1 with 8 byte from t0 -+ -+ +. if (v0 - 0x0101010101010101) & (~v0) & 0x8080808080808080 != 0, v0 has -+ one byte is \0, else has no \0 -+ -+ +. for partial 8 byte from ldr t3, 0(a0), preload t3 with 0xffffffffffffffff -+ -+ -+*/ -+#include -+#include -+ -+ -+#define STRNCMP strncmp -+ -+#define REP8_01 0x0101010101010101 -+#define REP8_7f 0x7f7f7f7f7f7f7f7f -+#define REP8_80 0x8080808080808080 -+ -+/* Parameters and Results */ -+#define src1 a0 -+#define src2 a1 -+#define limit a2 -+#define result v0 -+// Note: v0 = a0 in N64 ABI -+ -+ -+/* Internal variable */ -+#define data1 t0 -+#define data2 t1 -+#define has_nul t2 -+#define diff t3 -+#define syndrome t4 -+#define zeroones t5 -+#define sevenf t6 -+#define pos t7 -+#define exchange t8 -+#define tmp1 a5 -+#define tmp2 a6 -+#define tmp3 a7 -+#define src1_off a3 -+#define limit_wd a4 -+ -+ -+/* int strncmp (const char *s1, const char *s2); */ -+ -+LEAF(STRNCMP) -+ .align 4 -+ beqz limit, strncmp_ret0 -+ -+ xor tmp1, src1, src2 -+ lu12i.w zeroones, 0x01010 -+ lu12i.w sevenf, 0x7f7f7 -+ andi src1_off, src1, 0x7 -+ ori zeroones, zeroones, 0x101 -+ andi tmp1, tmp1, 0x7 -+ ori sevenf, sevenf, 0xf7f -+ bstrins.d zeroones, zeroones, 63, 32 -+ bstrins.d sevenf, sevenf, 63, 32 -+ bnez tmp1, strncmp_misaligned8 -+ bnez src1_off, strncmp_mutual_align -+ /* */ -+ addi.d limit_wd, limit, -1 -+ srli.d limit_wd, limit_wd, 3 -+ -+strncmp_loop_aligned: -+ ld.d data1, src1, 0 -+ addi.d src1, src1, 8 -+ ld.d data2, src2, 0 -+ addi.d src2, src2, 8 -+strncmp_start_realigned: -+ addi.d limit_wd, limit_wd, -1 -+ sub.d tmp1, data1, zeroones -+ or tmp2, data1, sevenf -+ xor diff, data1, data2 -+ andn has_nul, tmp1, tmp2 -+ srli.d tmp1, limit_wd, 63 -+ or syndrome, diff, has_nul -+ or tmp2, syndrome, tmp1 -+ beqz tmp2, strncmp_loop_aligned -+ -+ /* if not reach limit */ -+ bge limit_wd, zero, strncmp_not_limit -+ /* if reach limit */ -+ andi limit, limit, 0x7 -+ li.w tmp1, 0x8 -+ sub.d limit, tmp1, limit -+ slli.d limit, limit, 0x3 -+ li.d tmp1, -1 -+ srl.d tmp1, tmp1, limit -+ and data1, data1, tmp1 -+ and data2, data2, tmp1 -+ orn syndrome, syndrome, tmp1 -+ -+ -+strncmp_not_limit: -+ ctz.d pos, syndrome -+ bstrins.d pos, zero, 2, 0 -+ srl.d data1, data1, pos -+ srl.d data2, data2, pos -+ andi data1, data1, 0xff -+ andi data2, data2, 0xff -+ sub.d result, data1, data2 -+ jr ra -+ -+ -+ -+strncmp_mutual_align: -+ bstrins.d src1, zero, 2, 0 -+ bstrins.d src2, zero, 2, 0 -+ slli.d tmp1, src1_off, 0x3 -+ ld.d data1, src1, 0 -+ ld.d data2, src2, 0 -+ addi.d src2, src2, 8 -+ addi.d src1, src1, 8 -+ -+ addi.d limit_wd, limit, -1 -+ andi tmp3, limit_wd, 0x7 -+ srli.d limit_wd, limit_wd, 3 -+ add.d limit, limit, src1_off -+ add.d tmp3, tmp3, src1_off -+ srli.d tmp3, tmp3, 3 -+ add.d limit_wd, limit_wd, tmp3 -+ -+ sub.d tmp1, zero, tmp1 -+ nor tmp2, zero, zero -+ srl.d tmp2, tmp2, tmp1 -+ or data1, data1, tmp2 -+ or data2, data2, tmp2 -+ b strncmp_start_realigned -+ -+strncmp_misaligned8: -+ -+ li.w tmp1, 0x10 -+ bge limit, tmp1, strncmp_try_words -+strncmp_byte_loop: -+ ld.bu data1, src1, 0 -+ ld.bu data2, src2, 0 -+ addi.d limit, limit, -1 -+ xor tmp1, data1, data2 -+ masknez tmp1, data1, tmp1 -+ maskeqz tmp1, limit, tmp1 -+ beqz tmp1, strncmp_done -+ -+ ld.bu data1, src1, 1 -+ ld.bu data2, src2, 1 -+ addi.d src1, src1, 2 -+ addi.d src2, src2, 2 -+ addi.d limit, limit, -1 -+ xor tmp1, data1, data2 -+ masknez tmp1, data1, tmp1 -+ maskeqz tmp1, limit, tmp1 -+ bnez tmp1, strncmp_byte_loop -+ -+ -+strncmp_done: -+ sub.d result, data1, data2 -+ jr ra -+ -+strncmp_try_words: -+ srli.d limit_wd, limit, 3 -+ beqz src1_off, strncmp_do_misaligned -+ -+ sub.d src1_off, zero, src1_off -+ andi src1_off, src1_off, 0x7 -+ sub.d limit, limit, src1_off -+ srli.d limit_wd, limit, 0x3 -+ -+ -+strncmp_page_end_loop: -+ ld.bu data1, src1, 0 -+ ld.bu data2, src2, 0 -+ addi.d src1, src1, 1 -+ addi.d src2, src2, 1 -+ xor tmp1, data1, data2 -+ masknez tmp1, data1, tmp1 -+ beqz tmp1, strncmp_done -+ andi tmp1, src1, 0x7 -+ bnez tmp1, strncmp_page_end_loop -+strncmp_do_misaligned: -+ li.w src1_off, 0x8 -+ addi.d limit_wd, limit_wd, -1 -+ blt limit_wd, zero, strncmp_done_loop -+ -+strncmp_loop_misaligned: -+ andi tmp2, src2, 0xff8 -+ xori tmp2, tmp2, 0xff8 -+ beqz tmp2, strncmp_page_end_loop -+ -+ ld.d data1, src1, 0 -+ ld.d data2, src2, 0 -+ addi.d src1, src1, 8 -+ addi.d src2, src2, 8 -+ sub.d tmp1, data1, zeroones -+ or tmp2, data1, sevenf -+ xor diff, data1, data2 -+ andn has_nul, tmp1, tmp2 -+ or syndrome, diff, has_nul -+ bnez syndrome, strncmp_not_limit -+ addi.d limit_wd, limit_wd, -1 -+ #blt zero, limit_wd, strncmp_loop_misaligned -+ bge limit_wd, zero, strncmp_loop_misaligned -+ -+strncmp_done_loop: -+ andi limit, limit, 0x7 -+ beqz limit, strncmp_not_limit -+ /* Read the last double word */ -+ /* check if the final part is about to exceed the page */ -+ andi tmp1, src2, 0x7 -+ andi tmp2, src2, 0xff8 -+ add.d tmp1, tmp1, limit -+ xori tmp2, tmp2, 0xff8 -+ andi tmp1, tmp1, 0x8 -+ masknez tmp1, tmp1, tmp2 -+ bnez tmp1, strncmp_byte_loop -+ addi.d src1, src1, -8 -+ addi.d src2, src2, -8 -+ ldx.d data1, src1, limit -+ ldx.d data2, src2, limit -+ sub.d tmp1, data1, zeroones -+ or tmp2, data1, sevenf -+ xor diff, data1, data2 -+ andn has_nul, tmp1, tmp2 -+ or syndrome, diff, has_nul -+ bnez syndrome, strncmp_not_limit -+ -+strncmp_ret0: -+ move result, zero -+ jr ra -+/* check -+ if ((src1 != 0) && ((src2 == 0 ) || (src1 < src2))) -+ then exchange(src1,src2) -+ -+*/ -+ -+ -+ -+ -+ -+ -+END(STRNCMP) -+#ifndef ANDROID_CHANGES -+#ifdef _LIBC -+libc_hidden_builtin_def (strncmp) -+#endif -+#endif -diff --git a/sysdeps/loongarch/lp64/strnlen.S b/sysdeps/loongarch/lp64/strnlen.S -new file mode 100644 -index 00000000..3a204686 ---- /dev/null -+++ b/sysdeps/loongarch/lp64/strnlen.S -@@ -0,0 +1,155 @@ -+/* Copyright 2016 Loongson Technology Corporation Limited */ -+ -+/* Author: Songyuekun songyuekun@loongson.cn */ -+ -+/* -+ * ISA: MIPS64R2 -+ * ABI: N64 -+ */ -+/* -+algorithm: -+ -+ #. use ld/ldr to access word/partial word in the string -+ -+ #. use (x - 0x0101010101010101) & (~(x | 0x7f7f7f7f7f7f7f7f) != 0 to -+ judge if x has zero byte -+ -+ #. use dctz((x - 0x0101010101010101) & (~(x | 0x7f7f7f7f7f7f7f7f) >> 3 -+ to get the index of first rightmost zero byte in dword x; -+ -+ #. use dctz(x) = 64 - dclz(~x & (x-1)); -+ -+ #. use pointer to the last non zero byte minus pointer to the start -+ of the string to get the length of string -+ -+*/ -+ -+#include -+#include -+ -+ -+ -+#define L_ADDIU addi.d -+#define L_ADDU add.d -+#define L_SUBU sub.d -+ -+#define STRNLEN __strnlen -+#define L(x) x -+/* rd <- if rc then ra else rb -+ will destroy t6 -+*/ -+ -+#define CONDITIONSEL(rd,ra,rb,rc)\ -+ masknez a5, rb, rc;\ -+ maskeqz rd, ra, rc;\ -+ or rd, rd, a5 -+ -+ -+/* Parameters and Results */ -+#define srcin a0 -+#define limit a1 -+#define len v0 -+ -+ -+/* Internal variable */ -+#define data1 t0 -+#define data2 t1 -+#define has_nul1 t2 -+#define has_nul2 t3 -+#define src t4 -+#define zeroones t5 -+#define sevenf t6 -+#define data2a t7 -+#define tmp6 t7 -+#define pos t8 -+#define tmp1 a2 -+#define tmp2 a3 -+#define tmp3 a4 -+#define tmp4 a5 -+#define tmp5 a6 -+#define limit_wd a7 -+ -+ -+ -+/* size_t strnlen (const char *s1,size_t maxlen); */ -+ -+LEAF(STRNLEN) -+ -+ .align 4 -+ beqz limit, L(_hit_limit) -+ lu12i.w zeroones, 0x01010 -+ lu12i.w sevenf, 0x7f7f7 -+ ori zeroones, zeroones, 0x101 -+ ori sevenf, sevenf, 0xf7f -+ bstrins.d zeroones, zeroones, 63, 32 -+ bstrins.d sevenf, sevenf, 63, 32 -+ andi tmp1, srcin, 15 -+ sub.d src, srcin, tmp1 -+ bnez tmp1, L(misaligned) -+ addi.d limit_wd, limit, -1 -+ srli.d limit_wd, limit_wd, 4 -+L(_loop): -+ ld.d data1, src, 0 -+ ld.d data2, src, 8 -+ addi.d src, src, 16 -+L(_realigned): -+ sub.d tmp1, data1, zeroones -+ or tmp2, data1, sevenf -+ sub.d tmp3, data2, zeroones -+ or tmp4, data2, sevenf -+ andn has_nul1, tmp1, tmp2 -+ andn has_nul2, tmp3, tmp4 -+ addi.d limit_wd, limit_wd, -1 -+ srli.d tmp1, limit_wd, 63 -+ or tmp2, has_nul1, has_nul2 -+ or tmp3, tmp1, tmp2 -+ beqz tmp3, L(_loop) -+ beqz tmp2, L(_hit_limit) -+ sub.d len, src, srcin -+ beqz has_nul1, L(_nul_in_data2) -+ move has_nul2, has_nul1 -+ addi.d len, len, -8 -+L(_nul_in_data2): -+ ctz.d pos, has_nul2 -+ srli.d pos, pos, 3 -+ addi.d len, len, -8 -+ add.d len, len, pos -+ sltu tmp1, len, limit -+ CONDITIONSEL(len,len,limit,tmp1) -+ jr ra -+ -+ -+L(misaligned): -+ addi.d limit_wd, limit, -1 -+ sub.d tmp4, zero, tmp1 -+ andi tmp3, limit_wd, 15 -+ srli.d limit_wd, limit_wd, 4 -+ li.d tmp5, -1 -+ ld.d data1, src, 0 -+ ld.d data2, src, 8 -+ addi.d src, src, 16 -+ slli.d tmp4, tmp4, 3 -+ add.d tmp3, tmp3, tmp1 -+ srl.d tmp2, tmp5, tmp4 -+ srli.d tmp3, tmp3, 4 -+ add.d limit_wd, limit_wd, tmp3 -+ or data1, data1, tmp2 -+ or data2a, data2, tmp2 -+ li.w tmp3, 9 -+ sltu tmp1, tmp1, tmp3 -+ CONDITIONSEL(data1,data1,tmp5,tmp1) -+ CONDITIONSEL(data2,data2,data2a,tmp1) -+ b L(_realigned) -+ -+ -+L(_hit_limit): -+ move len, limit -+ jr ra -+END(STRNLEN) -+#ifndef ANDROID_CHANGES -+#ifdef _LIBC -+weak_alias (__strnlen, strnlen) -+libc_hidden_def (strnlen) -+libc_hidden_def (__strnlen) -+#endif -+#endif -diff --git a/sysdeps/loongarch/lstat.c b/sysdeps/loongarch/lstat.c -new file mode 100644 -index 00000000..f47a56af ---- /dev/null -+++ b/sysdeps/loongarch/lstat.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/lstat64.c b/sysdeps/loongarch/lstat64.c -new file mode 100644 -index 00000000..d6811656 ---- /dev/null -+++ b/sysdeps/loongarch/lstat64.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/machine-gmon.h b/sysdeps/loongarch/machine-gmon.h -new file mode 100644 -index 00000000..0b49082d ---- /dev/null -+++ b/sysdeps/loongarch/machine-gmon.h -@@ -0,0 +1,37 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+/* Accept 'frompc' address as argument from the function that calls -+ _mcount for profiling. Use __builtin_return_address (0) -+ for the 'selfpc' address. */ -+ -+#include -+ -+static void mcount_internal (unsigned long int frompc, -+ unsigned long int selfpc); -+ -+#define _MCOUNT_DECL(frompc, selfpc) \ -+static inline void mcount_internal (unsigned long int frompc, \ -+unsigned long int selfpc) -+ -+#define MCOUNT \ -+void _mcount (void *frompc) \ -+{ \ -+ mcount_internal ((unsigned long int) frompc, \ -+ (unsigned long int) RETURN_ADDRESS (0)); \ -+} -diff --git a/sysdeps/loongarch/math_private.h b/sysdeps/loongarch/math_private.h -new file mode 100644 -index 00000000..140eef07 ---- /dev/null -+++ b/sysdeps/loongarch/math_private.h -@@ -0,0 +1,245 @@ -+/* Internal math stuff. LOONGARCH version. -+ Copyright (C) 2013-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#ifndef LOONGARCH_MATH_PRIVATE_H -+#define LOONGARCH_MATH_PRIVATE_H 1 -+ -+/* Inline functions to speed up the math library implementation. The -+ default versions of these routines are in generic/math_private.h -+ and call fesetround, feholdexcept, etc. These routines use inlined -+ code instead. */ -+ -+#ifdef __loongarch_hard_float -+ -+# include -+# include -+# include -+ -+# define _FPU_MASK_ALL (_FPU_MASK_V | _FPU_MASK_Z | _FPU_MASK_O \ -+ |_FPU_MASK_U | _FPU_MASK_I | FE_ALL_EXCEPT) -+ -+static __always_inline void -+libc_feholdexcept_loongarch (fenv_t *envp) -+{ -+ fpu_control_t cw; -+ -+ /* Save the current state. */ -+ _FPU_GETCW (cw); -+ envp->__fp_control_register = cw; -+ -+ /* Clear all exception enable bits and flags. */ -+ cw &= ~(_FPU_MASK_ALL); -+ _FPU_SETCW (cw); -+} -+# define libc_feholdexcept libc_feholdexcept_loongarch -+# define libc_feholdexceptf libc_feholdexcept_loongarch -+# define libc_feholdexceptl libc_feholdexcept_loongarch -+ -+static __always_inline void -+libc_fesetround_loongarch (int round) -+{ -+ fpu_control_t cw; -+ -+ /* Get current state. */ -+ _FPU_GETCW (cw); -+ -+ /* Set rounding bits. */ -+ cw &= ~_FPU_RC_MASK; -+ cw |= round; -+ -+ /* Set new state. */ -+ _FPU_SETCW (cw); -+} -+# define libc_fesetround libc_fesetround_loongarch -+# define libc_fesetroundf libc_fesetround_loongarch -+# define libc_fesetroundl libc_fesetround_loongarch -+ -+static __always_inline void -+libc_feholdexcept_setround_loongarch (fenv_t *envp, int round) -+{ -+ fpu_control_t cw; -+ -+ /* Save the current state. */ -+ _FPU_GETCW (cw); -+ envp->__fp_control_register = cw; -+ -+ /* Clear all exception enable bits and flags. */ -+ cw &= ~(_FPU_MASK_ALL); -+ -+ /* Set rounding bits. */ -+ cw &= ~_FPU_RC_MASK; -+ cw |= round; -+ -+ /* Set new state. */ -+ _FPU_SETCW (cw); -+} -+# define libc_feholdexcept_setround libc_feholdexcept_setround_loongarch -+# define libc_feholdexcept_setroundf libc_feholdexcept_setround_loongarch -+# define libc_feholdexcept_setroundl libc_feholdexcept_setround_loongarch -+ -+# define libc_feholdsetround libc_feholdexcept_setround_loongarch -+# define libc_feholdsetroundf libc_feholdexcept_setround_loongarch -+# define libc_feholdsetroundl libc_feholdexcept_setround_loongarch -+ -+static __always_inline void -+libc_fesetenv_loongarch (fenv_t *envp) -+{ -+ fpu_control_t cw __attribute__ ((unused)); -+ -+ /* Read current state to flush fpu pipeline. */ -+ _FPU_GETCW (cw); -+ -+ _FPU_SETCW (envp->__fp_control_register); -+} -+# define libc_fesetenv libc_fesetenv_loongarch -+# define libc_fesetenvf libc_fesetenv_loongarch -+# define libc_fesetenvl libc_fesetenv_loongarch -+ -+static __always_inline int -+libc_feupdateenv_test_loongarch (fenv_t *envp, int excepts) -+{ -+ /* int ret = fetestexcept (excepts); feupdateenv (envp); return ret; */ -+ int cw, temp; -+ -+ /* Get current control word. */ -+ _FPU_GETCW (cw); -+ -+ /* Set flag bits (which are accumulative), and *also* set the -+ cause bits. The setting of the cause bits is what actually causes -+ the hardware to generate the exception, if the corresponding enable -+ bit is set as well. */ -+ temp = cw & FE_ALL_EXCEPT; -+ temp |= envp->__fp_control_register | (temp << CAUSE_SHIFT); -+ -+ /* Set new state. */ -+ _FPU_SETCW (temp); -+ -+ return cw & excepts & FE_ALL_EXCEPT; -+} -+# define libc_feupdateenv_test libc_feupdateenv_test_loongarch -+# define libc_feupdateenv_testf libc_feupdateenv_test_loongarch -+# define libc_feupdateenv_testl libc_feupdateenv_test_loongarch -+ -+static __always_inline void -+libc_feupdateenv_loongarch (fenv_t *envp) -+{ -+ libc_feupdateenv_test_loongarch (envp, 0); -+} -+# define libc_feupdateenv libc_feupdateenv_loongarch -+# define libc_feupdateenvf libc_feupdateenv_loongarch -+# define libc_feupdateenvl libc_feupdateenv_loongarch -+ -+# define libc_feresetround libc_feupdateenv_loongarch -+# define libc_feresetroundf libc_feupdateenv_loongarch -+# define libc_feresetroundl libc_feupdateenv_loongarch -+ -+static __always_inline int -+libc_fetestexcept_loongarch (int excepts) -+{ -+ int cw; -+ -+ /* Get current control word. */ -+ _FPU_GETCW (cw); -+ -+ return cw & excepts & FE_ALL_EXCEPT; -+} -+# define libc_fetestexcept libc_fetestexcept_loongarch -+# define libc_fetestexceptf libc_fetestexcept_loongarch -+# define libc_fetestexceptl libc_fetestexcept_loongarch -+ -+/* Enable support for rounding mode context. */ -+# define HAVE_RM_CTX 1 -+ -+static __always_inline void -+libc_feholdexcept_setround_loongarch_ctx (struct rm_ctx *ctx, int round) -+{ -+ fpu_control_t old, new; -+ -+ /* Save the current state. */ -+ _FPU_GETCW (old); -+ ctx->env.__fp_control_register = old; -+ -+ /* Clear all exception enable bits and flags. */ -+ new = old & ~(_FPU_MASK_ALL); -+ -+ /* Set rounding bits. */ -+ new = (new & ~_FPU_RC_MASK) | round; -+ -+ if (__glibc_unlikely (new != old)) -+ { -+ _FPU_SETCW (new); -+ ctx->updated_status = true; -+ } -+ else -+ ctx->updated_status = false; -+} -+# define libc_feholdexcept_setround_ctx libc_feholdexcept_setround_loongarch_ctx -+# define libc_feholdexcept_setroundf_ctx libc_feholdexcept_setround_loongarch_ctx -+# define libc_feholdexcept_setroundl_ctx libc_feholdexcept_setround_loongarch_ctx -+ -+static __always_inline void -+libc_fesetenv_loongarch_ctx (struct rm_ctx *ctx) -+{ -+ libc_fesetenv_loongarch (&ctx->env); -+} -+# define libc_fesetenv_ctx libc_fesetenv_loongarch_ctx -+# define libc_fesetenvf_ctx libc_fesetenv_loongarch_ctx -+# define libc_fesetenvl_ctx libc_fesetenv_loongarch_ctx -+ -+static __always_inline void -+libc_feupdateenv_loongarch_ctx (struct rm_ctx *ctx) -+{ -+ if (__glibc_unlikely (ctx->updated_status)) -+ libc_feupdateenv_test_loongarch (&ctx->env, 0); -+} -+# define libc_feupdateenv_ctx libc_feupdateenv_loongarch_ctx -+# define libc_feupdateenvf_ctx libc_feupdateenv_loongarch_ctx -+# define libc_feupdateenvl_ctx libc_feupdateenv_loongarch_ctx -+# define libc_feresetround_ctx libc_feupdateenv_loongarch_ctx -+# define libc_feresetroundf_ctx libc_feupdateenv_loongarch_ctx -+# define libc_feresetroundl_ctx libc_feupdateenv_loongarch_ctx -+ -+static __always_inline void -+libc_feholdsetround_loongarch_ctx (struct rm_ctx *ctx, int round) -+{ -+ fpu_control_t old, new; -+ -+ /* Save the current state. */ -+ _FPU_GETCW (old); -+ ctx->env.__fp_control_register = old; -+ -+ /* Set rounding bits. */ -+ new = (old & ~_FPU_RC_MASK) | round; -+ -+ if (__glibc_unlikely (new != old)) -+ { -+ _FPU_SETCW (new); -+ ctx->updated_status = true; -+ } -+ else -+ ctx->updated_status = false; -+} -+# define libc_feholdsetround_ctx libc_feholdsetround_loongarch_ctx -+# define libc_feholdsetroundf_ctx libc_feholdsetround_loongarch_ctx -+# define libc_feholdsetroundl_ctx libc_feholdsetround_loongarch_ctx -+ -+#endif -+ -+#include_next -+ -+#endif -diff --git a/sysdeps/loongarch/memusage.h b/sysdeps/loongarch/memusage.h -new file mode 100644 -index 00000000..bdf99f8a ---- /dev/null -+++ b/sysdeps/loongarch/memusage.h -@@ -0,0 +1,21 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+#define GETSP() ({ register uintptr_t stack_ptr asm ("$sp"); stack_ptr; }) -+ -+#include -diff --git a/sysdeps/loongarch/mknod.c b/sysdeps/loongarch/mknod.c -new file mode 100644 -index 00000000..1ed3681f ---- /dev/null -+++ b/sysdeps/loongarch/mknod.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/mknodat.c b/sysdeps/loongarch/mknodat.c -new file mode 100644 -index 00000000..82bc6ee6 ---- /dev/null -+++ b/sysdeps/loongarch/mknodat.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/nptl/Makefile b/sysdeps/loongarch/nptl/Makefile -new file mode 100644 -index 00000000..a1d5768a ---- /dev/null -+++ b/sysdeps/loongarch/nptl/Makefile -@@ -0,0 +1,26 @@ -+# Makefile for sysdeps/loongarch/nptl. -+# Copyright (C) 2005-2018 Free Software Foundation, Inc. -+# This file is part of the GNU C Library. -+# -+# The GNU C Library is free software; you can redistribute it and/or -+# modify it under the terms of the GNU Lesser General Public -+# License as published by the Free Software Foundation; either -+# version 2.1 of the License, or (at your option) any later version. -+# -+# The GNU C Library is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+# Lesser General Public License for more details. -+# -+# You should have received a copy of the GNU Lesser General Public -+# License along with the GNU C Library; if not, see -+# . -+ -+ifeq ($(subdir),csu) -+gen-as-const-headers += tcb-offsets.sym -+endif -+ -+ifeq ($(subdir),nptl) -+libpthread-sysdep_routines += nptl-sysdep -+libpthread-shared-only-routines += nptl-sysdep -+endif -diff --git a/sysdeps/loongarch/nptl/bits/pthreadtypes-arch.h b/sysdeps/loongarch/nptl/bits/pthreadtypes-arch.h -new file mode 100644 -index 00000000..5a761355 ---- /dev/null -+++ b/sysdeps/loongarch/nptl/bits/pthreadtypes-arch.h -@@ -0,0 +1,68 @@ -+/* Copyright (C) 2020-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 _BITS_PTHREADTYPES_ARCH_H -+#define _BITS_PTHREADTYPES_ARCH_H 1 -+ -+#include -+ -+#if __loongarch_xlen == 64 -+# define __SIZEOF_PTHREAD_ATTR_T 56 -+# define __SIZEOF_PTHREAD_MUTEX_T 40 -+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 -+# define __SIZEOF_PTHREAD_COND_T 48 -+# define __SIZEOF_PTHREAD_CONDATTR_T 4 -+# define __SIZEOF_PTHREAD_RWLOCK_T 56 -+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 -+# define __SIZEOF_PTHREAD_BARRIER_T 32 -+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 -+#else -+# error "rv32i-based systems are not supported" -+#endif -+ -+#define __PTHREAD_COMPAT_PADDING_MID -+#define __PTHREAD_COMPAT_PADDING_END -+#define __PTHREAD_MUTEX_LOCK_ELISION 0 -+#define __PTHREAD_MUTEX_USE_UNION 0 -+#define __PTHREAD_MUTEX_NUSERS_AFTER_KIND 0 -+ -+#define __LOCK_ALIGNMENT -+#define __ONCE_ALIGNMENT -+ -+/* There is a lot of padding in this structure. While it's not strictly -+ necessary on LoongArch, we're going to leave it in to be on the safe side in -+ case it's needed in the future. Most other architectures have the padding, -+ so this gives us the same extensibility as everyone else has. */ -+struct __pthread_rwlock_arch_t -+{ -+ unsigned int __readers; -+ unsigned int __writers; -+ unsigned int __wrphase_futex; -+ unsigned int __writers_futex; -+ unsigned int __pad3; -+ unsigned int __pad4; -+ int __cur_writer; -+ int __shared; -+ unsigned long int __pad1; -+ unsigned long int __pad2; -+ unsigned int __flags; -+}; -+ -+#define __PTHREAD_RWLOCK_ELISION_EXTRA 0 -+ -+#endif /* bits/pthreadtypes.h */ -diff --git a/sysdeps/loongarch/nptl/bits/semaphore.h b/sysdeps/loongarch/nptl/bits/semaphore.h -new file mode 100644 -index 00000000..a9ddefb2 ---- /dev/null -+++ b/sysdeps/loongarch/nptl/bits/semaphore.h -@@ -0,0 +1,33 @@ -+/* Copyright (C) 2020-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 _SEMAPHORE_H -+# error "Never use directly; include instead." -+#endif -+ -+#define __SIZEOF_SEM_T (4 * __SIZEOF_POINTER__) -+ -+/* Value returned if `sem_open' failed. */ -+#define SEM_FAILED ((sem_t *) 0) -+ -+ -+typedef union -+{ -+ char __size[__SIZEOF_SEM_T]; -+ long int __align; -+} sem_t; -diff --git a/sysdeps/loongarch/nptl/libc-lowlevellock.c b/sysdeps/loongarch/nptl/libc-lowlevellock.c -new file mode 100644 -index 00000000..9523fb46 ---- /dev/null -+++ b/sysdeps/loongarch/nptl/libc-lowlevellock.c -@@ -0,0 +1,8 @@ -+/* This kludge works around a libpthread static linking problem: -+ https://sourceware.org/bugzilla/show_bug.cgi?id=15648. */ -+ -+#ifndef SHARED -+# define __lll_lock_wait_private weak_function __lll_lock_wait_private -+#endif -+ -+#include -diff --git a/sysdeps/loongarch/nptl/nptl-sysdep.S b/sysdeps/loongarch/nptl/nptl-sysdep.S -new file mode 100644 -index 00000000..3f5c2a36 ---- /dev/null -+++ b/sysdeps/loongarch/nptl/nptl-sysdep.S -@@ -0,0 +1,2 @@ -+/* Pull in __syscall_error. */ -+#include -diff --git a/sysdeps/loongarch/nptl/pthread-offsets.h b/sysdeps/loongarch/nptl/pthread-offsets.h -new file mode 100644 -index 00000000..04130879 ---- /dev/null -+++ b/sysdeps/loongarch/nptl/pthread-offsets.h -@@ -0,0 +1,23 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+#define __PTHREAD_MUTEX_NUSERS_OFFSET 12 -+#define __PTHREAD_MUTEX_KIND_OFFSET 16 -+#define __PTHREAD_MUTEX_SPINS_OFFSET 20 -+#define __PTHREAD_MUTEX_ELISION_OFFSET 22 -+#define __PTHREAD_MUTEX_LIST_OFFSET 24 -diff --git a/sysdeps/loongarch/nptl/pthreaddef.h b/sysdeps/loongarch/nptl/pthreaddef.h -new file mode 100644 -index 00000000..87c407bc ---- /dev/null -+++ b/sysdeps/loongarch/nptl/pthreaddef.h -@@ -0,0 +1,32 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+/* Default stack size. */ -+#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) -+ -+/* Required stack pointer alignment at beginning. */ -+#define STACK_ALIGN 16 -+ -+/* Minimal stack size after allocating thread descriptor and guard size. */ -+#define MINIMAL_REST_STACK 2048 -+ -+/* Alignment requirement for TCB. */ -+#define TCB_ALIGNMENT 16 -+ -+/* Location of current stack frame. */ -+#define CURRENT_STACK_FRAME __builtin_frame_address (0) -diff --git a/sysdeps/loongarch/nptl/tcb-offsets.sym b/sysdeps/loongarch/nptl/tcb-offsets.sym -new file mode 100644 -index 00000000..ab4981f2 ---- /dev/null -+++ b/sysdeps/loongarch/nptl/tcb-offsets.sym -@@ -0,0 +1,6 @@ -+#include -+#include -+ -+#define thread_offsetof(mem) (long)(offsetof (struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) -+ -+MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) -diff --git a/sysdeps/loongarch/nptl/tls.h b/sysdeps/loongarch/nptl/tls.h -new file mode 100644 -index 00000000..8d2d4ca2 ---- /dev/null -+++ b/sysdeps/loongarch/nptl/tls.h -@@ -0,0 +1,147 @@ -+/* Copyright (C) 2020-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 _LOONGARCH_TLS_H -+#define _LOONGARCH_TLS_H 1 -+ -+#include -+ -+#ifndef __ASSEMBLER__ -+# include -+# include -+# include -+# include -+ -+register void *__thread_self asm ("$tp"); /* FIXME */ -+# define READ_THREAD_POINTER() ({ __thread_self; }) -+ -+/* Get system call information. */ -+# include -+ -+/* The TP points to the start of the thread blocks. */ -+# define TLS_DTV_AT_TP 1 -+# define TLS_TCB_AT_TP 0 -+ -+/* Get the thread descriptor definition. */ -+# include -+ -+typedef struct -+{ -+ dtv_t *dtv; -+ void *private; -+} tcbhead_t; -+ -+/* This is the size of the initial TCB. Because our TCB is before the thread -+ pointer, we don't need this. */ -+# define TLS_INIT_TCB_SIZE 0 -+ -+/* Alignment requirements for the initial TCB. */ -+# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) -+ -+/* This is the size of the TCB. Because our TCB is before the thread -+ pointer, we don't need this. */ -+# define TLS_TCB_SIZE 0 -+ -+/* Alignment requirements for the TCB. */ -+# define TLS_TCB_ALIGN __alignof__ (struct pthread) -+ -+/* This is the size we need before TCB - actually, it includes the TCB. */ -+# define TLS_PRE_TCB_SIZE \ -+ (sizeof (struct pthread) \ -+ + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) -+ -+/* The thread pointer tp points to the end of the TCB. -+ The pthread_descr structure is immediately in front of the TCB. */ -+# define TLS_TCB_OFFSET 0 -+ -+/* Install the dtv pointer. The pointer passed is to the element with -+ index -1 which contain the length. */ -+# define INSTALL_DTV(tcbp, dtvp) \ -+ (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1) -+ -+/* Install new dtv for current thread. */ -+# define INSTALL_NEW_DTV(dtv) \ -+ (THREAD_DTV() = (dtv)) -+ -+/* Return dtv of given thread descriptor. */ -+# define GET_DTV(tcbp) \ -+ (((tcbhead_t *) (tcbp))[-1].dtv) -+ -+/* Code to initially initialize the thread pointer. */ -+# define TLS_INIT_TP(tcbp) \ -+ ({ __thread_self = (char*)tcbp + TLS_TCB_OFFSET; NULL; }) -+ -+/* Return the address of the dtv for the current thread. */ -+# define THREAD_DTV() \ -+ (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv) -+ -+/* Return the thread descriptor for the current thread. */ -+# define THREAD_SELF \ -+ ((struct pthread *) (READ_THREAD_POINTER () \ -+ - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) -+ -+/* Value passed to 'clone' for initialization of the thread register. */ -+# define TLS_DEFINE_INIT_TP(tp, pd) \ -+ void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE -+ -+/* Informs libthread_db that the thread pointer is register 2, which is used -+ * to know how to do THREAD_SELF. */ -+# define DB_THREAD_SELF \ -+ REGISTER (64, 64, 2 * 8, - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) -+ -+/* Access to data in the thread descriptor is easy. */ -+# define THREAD_GETMEM(descr, member) \ -+ descr->member -+# define THREAD_GETMEM_NC(descr, member, idx) \ -+ descr->member[idx] -+# define THREAD_SETMEM(descr, member, value) \ -+ descr->member = (value) -+# define THREAD_SETMEM_NC(descr, member, idx, value) \ -+ descr->member[idx] = (value) -+ -+/* l_tls_offset == 0 is perfectly valid, so we have to use some different -+ value to mean unset l_tls_offset. */ -+# define NO_TLS_OFFSET -1 -+ -+/* Get and set the global scope generation counter in struct pthread. */ -+# define THREAD_GSCOPE_IN_TCB 1 -+# define THREAD_GSCOPE_FLAG_UNUSED 0 -+# define THREAD_GSCOPE_FLAG_USED 1 -+# define THREAD_GSCOPE_FLAG_WAIT 2 -+# define THREAD_GSCOPE_RESET_FLAG() \ -+ do \ -+ { int __res \ -+ = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \ -+ THREAD_GSCOPE_FLAG_UNUSED); \ -+ if (__res == THREAD_GSCOPE_FLAG_WAIT) \ -+ lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \ -+ } \ -+ while (0) -+# define THREAD_GSCOPE_SET_FLAG() \ -+ do \ -+ { \ -+ THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \ -+ atomic_write_barrier (); \ -+ } \ -+ while (0) -+# define THREAD_GSCOPE_WAIT() \ -+ GL(dl_wait_lookup_done) () -+ -+#endif /* __ASSEMBLER__ */ -+ -+#endif /* tls.h */ -diff --git a/sysdeps/loongarch/preconfigure b/sysdeps/loongarch/preconfigure -new file mode 100644 -index 00000000..26ffe884 ---- /dev/null -+++ b/sysdeps/loongarch/preconfigure -@@ -0,0 +1,9 @@ -+case "$machine" in -+loongarch*) -+ base_machine=loongarch -+ machine=loongarch/lp64 -+ ;; -+esac -+ -+#TODO: this file is useless now. -+#Maybe we can make use of it to get arch info from GCC to set env -diff --git a/sysdeps/loongarch/pthread_atfork.c b/sysdeps/loongarch/pthread_atfork.c -new file mode 100644 -index 00000000..0f01d805 ---- /dev/null -+++ b/sysdeps/loongarch/pthread_atfork.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/setjmp.S b/sysdeps/loongarch/setjmp.S -new file mode 100644 -index 00000000..da09a93c ---- /dev/null -+++ b/sysdeps/loongarch/setjmp.S -@@ -0,0 +1,62 @@ -+/* Copyright (C) 2020-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 -+ -+ENTRY (_setjmp) -+ li.w a1,0 -+ b __sigsetjmp -+END (_setjmp) -+ENTRY (setjmp) -+ li.w a1,1 -+END (setjmp) -+ENTRY (__sigsetjmp) -+ REG_S ra, a0, 0*SZREG -+ REG_S sp, a0, 1*SZREG -+ REG_S x, a0, 2*SZREG -+ REG_S fp, a0, 3*SZREG -+ REG_S s0, a0, 4*SZREG -+ REG_S s1, a0, 5*SZREG -+ REG_S s2, a0, 6*SZREG -+ REG_S s3, a0, 7*SZREG -+ REG_S s4, a0, 8*SZREG -+ REG_S s5, a0, 9*SZREG -+ REG_S s6, a0, 10*SZREG -+ REG_S s7, a0, 11*SZREG -+ REG_S s8, a0, 12*SZREG -+ -+ FREG_S $f24, a0, 13*SZREG + 0*SZFREG -+ FREG_S $f25, a0, 13*SZREG + 1*SZFREG -+ FREG_S $f26, a0, 13*SZREG + 2*SZFREG -+ FREG_S $f27, a0, 13*SZREG + 3*SZFREG -+ FREG_S $f28, a0, 13*SZREG + 4*SZFREG -+ FREG_S $f29, a0, 13*SZREG + 5*SZFREG -+ FREG_S $f30, a0, 13*SZREG + 6*SZFREG -+ FREG_S $f31, a0, 13*SZREG + 7*SZFREG -+ -+#if !IS_IN (libc) && IS_IN(rtld) -+ li.w v0, 0 -+ jirl zero,ra,0 -+#else -+ b __sigjmp_save -+#endif -+END (__sigsetjmp) -+ -+hidden_def (__sigsetjmp) -+weak_alias (_setjmp, __GI__setjmp) -diff --git a/sysdeps/loongarch/sfp-machine.h b/sysdeps/loongarch/sfp-machine.h -new file mode 100644 -index 00000000..b5c79bc0 ---- /dev/null -+++ b/sysdeps/loongarch/sfp-machine.h -@@ -0,0 +1,79 @@ -+#include -+#include -+ -+#define _FP_W_TYPE_SIZE 64 -+#define _FP_W_TYPE unsigned long long -+#define _FP_WS_TYPE signed long long -+#define _FP_I_TYPE long long -+ -+#define _FP_MUL_MEAT_S(R,X,Y) \ -+ _FP_MUL_MEAT_1_imm(_FP_WFRACBITS_S,R,X,Y) -+#define _FP_MUL_MEAT_D(R,X,Y) \ -+ _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) -+#define _FP_MUL_MEAT_Q(R,X,Y) \ -+ _FP_MUL_MEAT_2_wide_3mul(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) -+ -+#define _FP_MUL_MEAT_DW_S(R,X,Y) \ -+ _FP_MUL_MEAT_DW_1_imm(_FP_WFRACBITS_S,R,X,Y) -+#define _FP_MUL_MEAT_DW_D(R,X,Y) \ -+ _FP_MUL_MEAT_DW_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) -+#define _FP_MUL_MEAT_DW_Q(R,X,Y) \ -+ _FP_MUL_MEAT_DW_2_wide_3mul(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) -+ -+#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm) -+#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv_norm(D,R,X,Y) -+#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv(Q,R,X,Y) -+ -+# define _FP_NANFRAC_S _FP_QNANBIT_S -+# define _FP_NANFRAC_D _FP_QNANBIT_D -+# define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0 -+ -+#define _FP_NANSIGN_S 0 -+#define _FP_NANSIGN_D 0 -+#define _FP_NANSIGN_Q 0 -+ -+#define _FP_KEEPNANFRACP 1 -+#define _FP_QNANNEGATEDP 0 -+ -+/* NaN payloads should be preserved for NAN2008. */ -+# define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ -+ do \ -+ { \ -+ R##_s = X##_s; \ -+ _FP_FRAC_COPY_##wc (R, X); \ -+ R##_c = FP_CLS_NAN; \ -+ } \ -+ while (0) -+ -+#define _FP_DECL_EX fpu_control_t _fcw -+ -+#define FP_ROUNDMODE (_fcw & 0x300) -+ -+#define FP_RND_NEAREST FE_TONEAREST -+#define FP_RND_ZERO FE_TOWARDZERO -+#define FP_RND_PINF FE_UPWARD -+#define FP_RND_MINF FE_DOWNWARD -+ -+#define FP_EX_INVALID FE_INVALID -+#define FP_EX_OVERFLOW FE_OVERFLOW -+#define FP_EX_UNDERFLOW FE_UNDERFLOW -+#define FP_EX_DIVZERO FE_DIVBYZERO -+#define FP_EX_INEXACT FE_INEXACT -+ -+#define _FP_TININESS_AFTER_ROUNDING 1 -+ -+#ifdef __loongarch_hard_float -+#define FP_INIT_ROUNDMODE \ -+do { \ -+ _FPU_GETCW (_fcw); \ -+} while (0) -+ -+#define FP_HANDLE_EXCEPTIONS \ -+do { \ -+ if (__builtin_expect (_fex, 0)) \ -+ _FPU_SETCW (_fcw | _fex | (_fex << 8)); \ -+} while (0) -+#define FP_TRAPPING_EXCEPTIONS ((_fcw << 16) & 0x1f0000) -+#else -+#define FP_INIT_ROUNDMODE _fcw = FP_RND_NEAREST -+#endif -diff --git a/sysdeps/loongarch/sotruss-lib.c b/sysdeps/loongarch/sotruss-lib.c -new file mode 100644 -index 00000000..124db440 ---- /dev/null -+++ b/sysdeps/loongarch/sotruss-lib.c -@@ -0,0 +1,51 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+#define HAVE_ARCH_PLTENTER -+#define HAVE_ARCH_PLTEXIT -+ -+#include -+ -+ElfW(Addr) -+la_loongarch_gnu_pltenter (ElfW(Sym) *sym __attribute__ ((unused)), -+ unsigned int ndx __attribute__ ((unused)), -+ uintptr_t *refcook, uintptr_t *defcook, -+ La_loongarch_regs *regs, unsigned int *flags, -+ const char *symname, long int *framesizep) -+{ -+ print_enter (refcook, defcook, symname, -+ regs->lr_reg[0], regs->lr_reg[1], regs->lr_reg[2], -+ *flags); -+ -+ /* No need to copy anything, we will not need the parameters in any case. */ -+ *framesizep = 0; -+ -+ return sym->st_value; -+} -+ -+unsigned int -+la_loongarch_gnu_pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, -+ uintptr_t *defcook, -+ const struct La_loongarch_regs *inregs, -+ struct La_loongarch_retval *outregs, -+ const char *symname) -+{ -+ print_exit (refcook, defcook, symname, outregs->lrv_a0); -+ -+ return 0; -+} -diff --git a/sysdeps/loongarch/stack_chk_fail_local.c b/sysdeps/loongarch/stack_chk_fail_local.c -new file mode 100644 -index 00000000..305871fb ---- /dev/null -+++ b/sysdeps/loongarch/stack_chk_fail_local.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/stackinfo.h b/sysdeps/loongarch/stackinfo.h -new file mode 100644 -index 00000000..5f5e6ad1 ---- /dev/null -+++ b/sysdeps/loongarch/stackinfo.h -@@ -0,0 +1,33 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+/* This file contains a bit of information about the stack allocation -+ of the processor. */ -+ -+#ifndef _STACKINFO_H -+#define _STACKINFO_H 1 -+ -+#include -+ -+/* On LoongArch the stack grows down. */ -+#define _STACK_GROWS_DOWN 1 -+ -+/* Default to a non-executable stack. */ -+#define DEFAULT_STACK_PERMS (PF_R | PF_W) -+ -+#endif /* stackinfo.h */ -diff --git a/sysdeps/loongarch/start.S b/sysdeps/loongarch/start.S -new file mode 100644 -index 00000000..cf0a14b5 ---- /dev/null -+++ b/sysdeps/loongarch/start.S -@@ -0,0 +1,51 @@ -+#define __ASSEMBLY__ 1 -+#include -+#include -+ -+/* The entry point's job is to call __libc_start_main. Per the ABI, -+ a0 contains the address of a function to be passed to atexit. -+ __libc_start_main wants this in a5. */ -+ -+/* -+int -+__libc_start_main (int (*main) (int, char **, char **), -+ int argc, -+ char **argv, -+ __typeof (main) init, -+ void (*fini) (void), -+ void (*rtld_fini) (void), -+ void *stack_end); -+*/ -+ -+ENTRY (ENTRY_POINT) -+ /* Terminate call stack by noting ra is undefined. Use a dummy -+ .cfi_label to force starting the FDE. */ -+ .cfi_label .Ldummy -+ cfi_undefined (1) -+ or a5, a0, zero /* rtld_fini */ -+ -+ /* 这个main必须要走GOT表拿到。因为main不一定是local的。 -+ 比如googletest就把main定义在动态库里了。 */ -+ la.got a0, t0, main -+#ifdef __loongarch64 -+ ld.d a1, sp, 0 -+ addi.d a2, sp, SZREG -+#elif defined __loongarch32 -+ ld.w a1, sp, 0 -+ addi.w a2, sp, SZREG -+#endif -+ /* Adjust $sp for 16-aligned */ -+ srli.d sp, sp, 4 -+ slli.d sp, sp, 4 -+ -+ la.got a3, t0, __libc_csu_init -+ la.got a4, t0, __libc_csu_fini -+ or a6, sp, zero /* stack_end. */ -+ -+ la.got ra, t0, __libc_start_main -+ jirl ra, ra, 0 -+ -+ la.got ra, t0, abort -+ jirl ra, ra, 0 -+END (ENTRY_POINT) -+ -diff --git a/sysdeps/loongarch/stat.c b/sysdeps/loongarch/stat.c -new file mode 100644 -index 00000000..36461b87 ---- /dev/null -+++ b/sysdeps/loongarch/stat.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/stat64.c b/sysdeps/loongarch/stat64.c -new file mode 100644 -index 00000000..0897282e ---- /dev/null -+++ b/sysdeps/loongarch/stat64.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/loongarch/sys/asm.h b/sysdeps/loongarch/sys/asm.h -new file mode 100644 -index 00000000..7f3769bd ---- /dev/null -+++ b/sysdeps/loongarch/sys/asm.h -@@ -0,0 +1,49 @@ -+#ifndef _SYS_ASM_H -+#define _SYS_ASM_H -+ -+#include -+#include -+ -+/* Macros to handle different pointer/register sizes for 32/64-bit code. */ -+#ifdef __loongarch64 -+# define PTRLOG 3 -+# define SZREG 8 -+# define SZFREG 8 -+# define REG_L ld.d -+# define REG_S st.d -+# define FREG_L fld.d -+# define FREG_S fst.d -+#elif defined __loongarch32 -+# define PTRLOG 2 -+# define SZREG 4 -+# define SZFREG 4 -+# define REG_L ld.w -+# define REG_S st.w -+# define FREG_L fld.w -+# define FREG_S fst.w -+#else -+# error __loongarch_xlen must equal 32 or 64 -+#endif -+ -+ -+/* Declare leaf routine. */ -+#define LEAF(symbol) \ -+ .text; \ -+ .globl symbol; \ -+ .align 3; \ -+ cfi_startproc ; \ -+ .type symbol, @function; \ -+symbol: -+ -+# define ENTRY(symbol) LEAF(symbol) -+ -+/* Mark end of function. */ -+#undef END -+#define END(function) \ -+ cfi_endproc ; \ -+ .size function,.-function; -+ -+/* Stack alignment. */ -+#define ALMASK ~15 -+ -+#endif /* sys/asm.h */ -diff --git a/sysdeps/loongarch/sys/regdef.h b/sysdeps/loongarch/sys/regdef.h -new file mode 100644 -index 00000000..769784b8 ---- /dev/null -+++ b/sysdeps/loongarch/sys/regdef.h -@@ -0,0 +1,83 @@ -+#ifndef _SYS_REGDEF_H -+#define _SYS_REGDEF_H -+ -+#if _LOONGARCH_SIM == _ABILP64 -+# define zero $r0 -+# define ra $r1 -+# define tp $r2 -+# define sp $r3 -+# define a0 $r4 -+# define a1 $r5 -+# define a2 $r6 -+# define a3 $r7 -+# define a4 $r8 -+# define a5 $r9 -+# define a6 $r10 -+# define a7 $r11 -+# define v0 $r4 -+# define v1 $r5 -+# define t0 $r12 -+# define t1 $r13 -+# define t2 $r14 -+# define t3 $r15 -+# define t4 $r16 -+# define t5 $r17 -+# define t6 $r18 -+# define t7 $r19 -+# define t8 $r20 -+# define x $r21 -+# define fp $r22 -+# define s0 $r23 -+# define s1 $r24 -+# define s2 $r25 -+# define s3 $r26 -+# define s4 $r27 -+# define s5 $r28 -+# define s6 $r29 -+# define s7 $r30 -+# define s8 $r31 -+ -+# define fa0 $f0 -+# define fa1 $f1 -+# define fa2 $f2 -+# define fa3 $f3 -+# define fa4 $f4 -+# define fa5 $f5 -+# define fa6 $f6 -+# define fa7 $f7 -+# define fv0 $f0 -+# define fv1 $f1 -+# define ft0 $f8 -+# define ft1 $f9 -+# define ft2 $f10 -+# define ft3 $f11 -+# define ft4 $f12 -+# define ft5 $f13 -+# define ft6 $f14 -+# define ft7 $f15 -+# define ft8 $f16 -+# define ft9 $f17 -+# define ft10 $f18 -+# define ft11 $f19 -+# define ft12 $f20 -+# define ft13 $f21 -+# define ft14 $f22 -+# define ft15 $f23 -+# define fs0 $f24 -+# define fs1 $f25 -+# define fs2 $f26 -+# define fs3 $f27 -+# define fs4 $f28 -+# define fs5 $f29 -+# define fs6 $f30 -+# define fs7 $f31 -+ -+#elif _LOONGARCH_SIM == _ABILPX32 -+# error ABILPX32 -+#elif _LOONGARCH_SIM == _ABILP32 -+# error ABILP32 -+#else -+# error noABI -+#endif -+ -+#endif /* _SYS_REGDEF_H */ -diff --git a/sysdeps/loongarch/tininess.h b/sysdeps/loongarch/tininess.h -new file mode 100644 -index 00000000..1db37790 ---- /dev/null -+++ b/sysdeps/loongarch/tininess.h -@@ -0,0 +1 @@ -+#define TININESS_AFTER_ROUNDING 1 -diff --git a/sysdeps/loongarch/tls-macros.h b/sysdeps/loongarch/tls-macros.h -new file mode 100644 -index 00000000..f0ad55ac ---- /dev/null -+++ b/sysdeps/loongarch/tls-macros.h -@@ -0,0 +1,46 @@ -+/* Macros to support TLS testing in times of missing compiler support. -+ Copyright (C) 2017-2018 Free Software Foundation, Inc. -+ -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+ -+#include -+#include -+#include -+#include "dl-tls.h" -+ -+#define TLS_GD(x) \ -+ ({ void *__result; \ -+ asm ("la.tls.gd %0, " #x "\n\t" \ -+ : "=r" (__result)); \ -+ __tls_get_addr (__result); }) -+ -+#define TLS_LD(x) TLS_GD(x) -+ -+#define TLS_IE(x) \ -+ ({ void *__result; \ -+ asm ("la.tls.ie %0, " #x "\n\t" \ -+ "add.d %0, %0, $tp\n\t" \ -+ : "=r" (__result)); \ -+ __result; }) -+ -+#define TLS_LE(x) \ -+ ({ void *__result; \ -+ asm ("la.tls.le %0, " #x "\n\t" \ -+ "add.d %0, %0, $tp\n\t" \ -+ : "=r" (__result)); \ -+ __result; }) -diff --git a/sysdeps/loongarch/tst-audit.h b/sysdeps/loongarch/tst-audit.h -new file mode 100644 -index 00000000..d8d260eb ---- /dev/null -+++ b/sysdeps/loongarch/tst-audit.h -@@ -0,0 +1,23 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+#define pltenter la_loongarch_gnu_pltenter -+#define pltexit la_loongarch_gnu_pltexit -+#define La_regs La_loongarch_regs -+#define La_retval La_loongarch_retval -+#define int_retval lrv_a0 -diff --git a/sysdeps/loongarch/warning-nop.c b/sysdeps/loongarch/warning-nop.c -new file mode 100644 -index 00000000..b76aae79 ---- /dev/null -+++ b/sysdeps/loongarch/warning-nop.c -@@ -0,0 +1 @@ -+#include -diff --git a/sysdeps/unix/sysv/linux/loongarch/Implies b/sysdeps/unix/sysv/linux/loongarch/Implies -new file mode 100644 -index 00000000..e52b1ac3 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/Implies -@@ -0,0 +1 @@ -+loongarch/nptl -diff --git a/sysdeps/unix/sysv/linux/loongarch/Makefile b/sysdeps/unix/sysv/linux/loongarch/Makefile -new file mode 100644 -index 00000000..6f049aa9 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/Makefile -@@ -0,0 +1,17 @@ -+ifeq ($(subdir),elf) -+sysdep_routines += dl-vdso -+ifeq ($(build-shared),yes) -+# This is needed for DSO loading from static binaries. -+sysdep-dl-routines += dl-static -+endif -+endif -+ -+#ifeq ($(subdir),misc) -+#sysdep_headers += sys/cachectl.h -+#sysdep_routines += flush-icache -+#endif -+ -+ifeq ($(subdir),stdlib) -+gen-as-const-headers += ucontext_i.sym -+endif -+ -diff --git a/sysdeps/unix/sysv/linux/loongarch/Versions b/sysdeps/unix/sysv/linux/loongarch/Versions -new file mode 100644 -index 00000000..453f276a ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/Versions -@@ -0,0 +1,44 @@ -+ld { -+ GLIBC_PRIVATE { -+ # used for loading by static libraries -+ _dl_var_init; -+ } -+} -+libc { -+ # The comment lines with "#errlist-compat" are magic; see errlist-compat.awk. -+ # When you get an error from errlist-compat.awk, you need to add a new -+ # version here. Don't do this blindly, since this means changing the ABI -+ # for all GNU/Linux configurations. -+ -+ GLIBC_2.0 { -+ #errlist-compat 123 -+ _sys_errlist; sys_errlist; _sys_nerr; sys_nerr; -+ -+ # Exception handling support functions from libgcc -+ __register_frame; __register_frame_table; __deregister_frame; -+ __frame_state_for; __register_frame_info_table; -+ -+ # Needed by gcc: -+ _flush_cache; -+ -+ # c* -+ cachectl; cacheflush; -+ -+ # s* -+ sysmips; -+ } -+ GLIBC_2.2 { -+ #errlist-compat 1134 -+ _sys_errlist; sys_errlist; _sys_nerr; sys_nerr; -+ -+ # _* -+ _test_and_set; -+ } -+ GLIBC_2.11 { -+ fallocate64; -+ } -+ GLIBC_PRIVATE { -+ # nptl/pthread_cond_timedwait.c uses INTERNAL_VSYSCALL(clock_gettime). -+ __vdso_clock_gettime; -+ } -+} -diff --git a/sysdeps/unix/sysv/linux/loongarch/atomic-machine.h b/sysdeps/unix/sysv/linux/loongarch/atomic-machine.h -new file mode 100644 -index 00000000..ac1948ea ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/atomic-machine.h -@@ -0,0 +1,188 @@ -+/* Copyright (C) 2020-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 _LINUX_LOONGARCH_BITS_ATOMIC_H -+#define _LINUX_LOONGARCH_BITS_ATOMIC_H 1 -+ -+#include -+ -+typedef int32_t atomic32_t; -+typedef uint32_t uatomic32_t; -+ -+typedef int64_t atomic64_t; -+typedef uint64_t uatomic64_t; -+ -+typedef intptr_t atomicptr_t; -+typedef uintptr_t uatomicptr_t; -+typedef intmax_t atomic_max_t; -+typedef uintmax_t uatomic_max_t; -+ -+#define atomic_full_barrier() __sync_synchronize () -+ -+# define __HAVE_64B_ATOMICS (__loongarch_xlen >= 64) -+# define USE_ATOMIC_COMPILER_BUILTINS 1 -+# define ATOMIC_EXCHANGE_USES_CAS 0 -+ -+/* Compare and exchange. -+ For all "bool" routines, we return FALSE if exchange succesful. */ -+ -+# define __arch_compare_and_exchange_bool_8_int(mem, newval, oldval, model) \ -+ ({ \ -+ typeof (*mem) __oldval = (oldval); \ -+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \ -+ model, __ATOMIC_RELAXED); \ -+ }) -+ -+# define __arch_compare_and_exchange_bool_16_int(mem, newval, oldval, model) \ -+ ({ \ -+ typeof (*mem) __oldval = (oldval); \ -+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \ -+ model, __ATOMIC_RELAXED); \ -+ }) -+ -+# define __arch_compare_and_exchange_bool_32_int(mem, newval, oldval, model) \ -+ ({ \ -+ typeof (*mem) __oldval = (oldval); \ -+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \ -+ model, __ATOMIC_RELAXED); \ -+ }) -+ -+# define __arch_compare_and_exchange_bool_64_int(mem, newval, oldval, model) \ -+ ({ \ -+ typeof (*mem) __oldval = (oldval); \ -+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \ -+ model, __ATOMIC_RELAXED); \ -+ }) -+ -+# define __arch_compare_and_exchange_val_8_int(mem, newval, oldval, model) \ -+ ({ \ -+ typeof (*mem) __oldval = (oldval); \ -+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \ -+ model, __ATOMIC_RELAXED); \ -+ __oldval; \ -+ }) -+ -+# define __arch_compare_and_exchange_val_16_int(mem, newval, oldval, model) \ -+ ({ \ -+ typeof (*mem) __oldval = (oldval); \ -+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \ -+ model, __ATOMIC_RELAXED); \ -+ __oldval; \ -+ }) -+ -+# define __arch_compare_and_exchange_val_32_int(mem, newval, oldval, model) \ -+ ({ \ -+ typeof (*mem) __oldval = (oldval); \ -+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \ -+ model, __ATOMIC_RELAXED); \ -+ __oldval; \ -+ }) -+ -+# define __arch_compare_and_exchange_val_64_int(mem, newval, oldval, model) \ -+ ({ \ -+ typeof (*mem) __oldval = (oldval); \ -+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \ -+ model, __ATOMIC_RELAXED); \ -+ __oldval; \ -+ }) -+ -+/* Atomic compare and exchange. */ -+ -+# define atomic_compare_and_exchange_bool_acq(mem, new, old) \ -+ __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \ -+ mem, new, old, __ATOMIC_ACQUIRE) -+ -+# define atomic_compare_and_exchange_val_acq(mem, new, old) \ -+ __atomic_val_bysize (__arch_compare_and_exchange_val, int, \ -+ mem, new, old, __ATOMIC_ACQUIRE) -+ -+# define atomic_compare_and_exchange_val_rel(mem, new, old) \ -+ __atomic_val_bysize (__arch_compare_and_exchange_val, int, \ -+ mem, new, old, __ATOMIC_RELEASE) -+ -+/* Atomic exchange (without compare). */ -+ -+# define __arch_exchange_8_int(mem, newval, model) \ -+ __atomic_exchange_n (mem, newval, model) -+ -+# define __arch_exchange_16_int(mem, newval, model) \ -+ __atomic_exchange_n (mem, newval, model) -+ -+# define __arch_exchange_32_int(mem, newval, model) \ -+ __atomic_exchange_n (mem, newval, model) -+ -+# define __arch_exchange_64_int(mem, newval, model) \ -+ __atomic_exchange_n (mem, newval, model) -+ -+# define atomic_exchange_acq(mem, value) \ -+ __atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_ACQUIRE) -+ -+# define atomic_exchange_rel(mem, value) \ -+ __atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_RELEASE) -+ -+/* Atomically add value and return the previous (unincremented) value. */ -+ -+# define __arch_exchange_and_add_8_int(mem, value, model) \ -+ __atomic_fetch_add (mem, value, model) -+ -+# define __arch_exchange_and_add_16_int(mem, value, model) \ -+ __atomic_fetch_add (mem, value, model) -+ -+# define __arch_exchange_and_add_32_int(mem, value, model) \ -+ __atomic_fetch_add (mem, value, model) -+ -+# define __arch_exchange_and_add_64_int(mem, value, model) \ -+ __atomic_fetch_add (mem, value, model) -+ -+# define atomic_exchange_and_add_acq(mem, value) \ -+ __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, \ -+ __ATOMIC_ACQUIRE) -+ -+# define atomic_exchange_and_add_rel(mem, value) \ -+ __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, \ -+ __ATOMIC_RELEASE) -+ -+/* Miscellaneous. */ -+ -+# define asm_amo(which, mem, value) ({ \ -+ __atomic_check_size (mem); \ -+ typeof (*mem) __tmp; \ -+ if (sizeof (__tmp) == 4) \ -+ asm volatile (which ".w""\t%0, %z2, %1" \ -+ : "=&r" (__tmp), "+ZB" (* (mem)) \ -+ : "rJ" (value)); \ -+ else if (sizeof (__tmp) == 8) \ -+ asm volatile (which ".d""\t%0, %z2, %1" \ -+ : "=&r" (__tmp), "+ZB" (* (mem)) \ -+ : "rJ" (value)); \ -+ else \ -+ abort (); \ -+ __tmp; }) -+ -+# define atomic_max(mem, value) asm_amo ("ammax_db", mem, value) -+# define atomic_min(mem, value) asm_amo ("ammin_db", mem, value) -+ -+# define atomic_bit_test_set(mem, bit) \ -+ ({ typeof (*mem) __mask = (typeof (*mem))1 << (bit); \ -+ asm_amo("amor_db", mem, __mask) & __mask; }) -+ -+# define catomic_exchange_and_add(mem, value) \ -+ atomic_exchange_and_add (mem, value) -+# define catomic_max(mem, value) atomic_max (mem, value) -+ -+#endif /* bits/atomic.h */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/bits/fcntl.h b/sysdeps/unix/sysv/linux/loongarch/bits/fcntl.h -new file mode 100644 -index 00000000..5ee2e976 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/bits/fcntl.h -@@ -0,0 +1,62 @@ -+/* O_*, F_*, FD_* bit values for the generic Linux ABI. -+ Copyright (C) 2011-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Chris Metcalf , 2011. -+ -+ 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 _FCNTL_H -+# error "Never use directly; include instead." -+#endif -+ -+#include -+ -+/* In 64-bit ISA files are always with 64bit off_t and F_*LK64 are the same as -+ non-64-bit versions. It will need to be revised for 128-bit. */ -+#if __WORDSIZE == 64 -+# define __O_LARGEFILE 0 -+ -+# define F_GETLK64 5 /* Get record locking info. */ -+# define F_SETLK64 6 /* Set record locking info (non-blocking). */ -+# define F_SETLKW64 7 /* Set record locking info (blocking). */ -+#endif -+ -+struct flock -+ { -+ short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */ -+ short int l_whence; /* Where `l_start' is relative to (like `lseek'). */ -+#ifndef __USE_FILE_OFFSET64 -+ __off_t l_start; /* Offset where the lock begins. */ -+ __off_t l_len; /* Size of the locked area; zero means until EOF. */ -+#else -+ __off64_t l_start; /* Offset where the lock begins. */ -+ __off64_t l_len; /* Size of the locked area; zero means until EOF. */ -+#endif -+ __pid_t l_pid; /* Process holding the lock. */ -+ }; -+ -+#ifdef __USE_LARGEFILE64 -+struct flock64 -+ { -+ short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */ -+ short int l_whence; /* Where `l_start' is relative to (like `lseek'). */ -+ __off64_t l_start; /* Offset where the lock begins. */ -+ __off64_t l_len; /* Size of the locked area; zero means until EOF. */ -+ __pid_t l_pid; /* Process holding the lock. */ -+ }; -+#endif -+ -+/* Include generic Linux declarations. */ -+#include -diff --git a/sysdeps/unix/sysv/linux/loongarch/bits/local_lim.h b/sysdeps/unix/sysv/linux/loongarch/bits/local_lim.h -new file mode 100644 -index 00000000..a8cd6df8 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/bits/local_lim.h -@@ -0,0 +1,99 @@ -+/* Minimum guaranteed maximum values for system limits. Linux version. -+ Copyright (C) 1993-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of the -+ License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; see the file COPYING.LIB. If -+ not, see . */ -+ -+/* The kernel header pollutes the namespace with the NR_OPEN symbol -+ and defines LINK_MAX although filesystems have different maxima. A -+ similar thing is true for OPEN_MAX: the limit can be changed at -+ runtime and therefore the macro must not be defined. Remove this -+ after including the header if necessary. */ -+#ifndef NR_OPEN -+# define __undef_NR_OPEN -+#endif -+#ifndef LINK_MAX -+# define __undef_LINK_MAX -+#endif -+#ifndef OPEN_MAX -+# define __undef_OPEN_MAX -+#endif -+#ifndef ARG_MAX -+# define __undef_ARG_MAX -+#endif -+ -+/* The kernel sources contain a file with all the needed information. */ -+#include -+ -+/* Have to remove NR_OPEN? */ -+#ifdef __undef_NR_OPEN -+# undef NR_OPEN -+# undef __undef_NR_OPEN -+#endif -+/* Have to remove LINK_MAX? */ -+#ifdef __undef_LINK_MAX -+# undef LINK_MAX -+# undef __undef_LINK_MAX -+#endif -+/* Have to remove OPEN_MAX? */ -+#ifdef __undef_OPEN_MAX -+# undef OPEN_MAX -+# undef __undef_OPEN_MAX -+#endif -+/* Have to remove ARG_MAX? */ -+#ifdef __undef_ARG_MAX -+# undef ARG_MAX -+# undef __undef_ARG_MAX -+#endif -+ -+/* The number of data keys per process. */ -+#define _POSIX_THREAD_KEYS_MAX 128 -+/* This is the value this implementation supports. */ -+#define PTHREAD_KEYS_MAX 1024 -+ -+/* Controlling the iterations of destructors for thread-specific data. */ -+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 -+/* Number of iterations this implementation does. */ -+#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS -+ -+/* The number of threads per process. */ -+#define _POSIX_THREAD_THREADS_MAX 64 -+/* We have no predefined limit on the number of threads. */ -+#undef PTHREAD_THREADS_MAX -+ -+/* Maximum amount by which a process can descrease its asynchronous I/O -+ priority level. */ -+#define AIO_PRIO_DELTA_MAX 20 -+ -+/* Minimum size for a thread. At least two pages with 64k pages. */ -+#define PTHREAD_STACK_MIN 131072 -+ -+/* Maximum number of timer expiration overruns. */ -+#define DELAYTIMER_MAX 2147483647 -+ -+/* Maximum tty name length. */ -+#define TTY_NAME_MAX 32 -+ -+/* Maximum login name length. This is arbitrary. */ -+#define LOGIN_NAME_MAX 256 -+ -+/* Maximum host name length. */ -+#define HOST_NAME_MAX 64 -+ -+/* Maximum message queue priority level. */ -+#define MQ_PRIO_MAX 32768 -+ -+/* Maximum value the semaphore can have. */ -+#define SEM_VALUE_MAX (2147483647) -diff --git a/sysdeps/unix/sysv/linux/loongarch/bits/mman.h b/sysdeps/unix/sysv/linux/loongarch/bits/mman.h -new file mode 100644 -index 00000000..5a16f8ac ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/bits/mman.h -@@ -0,0 +1,41 @@ -+/* Definitions for POSIX memory map interface. Linux/MIPS version. -+ Copyright (C) 1997-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+ -+#ifndef _SYS_MMAN_H -+# error "Never use directly; include instead." -+#endif -+ -+#ifdef __USE_MISC -+# define MAP_GROWSDOWN 0x00100 /* Stack-like segment. */ -+# define MAP_DENYWRITE 0x00800 /* ETXTBSY. */ -+# define MAP_EXECUTABLE 0x01000 /* Mark it as an executable. */ -+# define MAP_LOCKED 0x02000 /* Lock the mapping. */ -+# define MAP_NORESERVE 0x04000 /* Don't check for reservations. */ -+# define MAP_POPULATE 0x08000 /* Populate (prefault) pagetables. */ -+# define MAP_NONBLOCK 0x10000 /* Do not block on IO. */ -+# define MAP_STACK 0x20000 /* Allocation is for a stack. */ -+# define MAP_HUGETLB 0x40000 /* Create huge page mapping. */ -+# define MAP_SYNC 0x80000 /* Perform synchronous page -+ faults for the mapping. */ -+# define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED but do not unmap -+ underlying mapping. */ -+#endif -+ -+/* Include generic Linux declarations. */ -+#include -diff --git a/sysdeps/unix/sysv/linux/loongarch/bits/shm.h b/sysdeps/unix/sysv/linux/loongarch/bits/shm.h -new file mode 100644 -index 00000000..9e23092d ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/bits/shm.h -@@ -0,0 +1,112 @@ -+/* Copyright (C) 2011-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Chris Metcalf , 2011. -+ -+ 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 _SYS_SHM_H -+# error "Never include directly; use instead." -+#endif -+ -+#include -+#include -+ -+/* Permission flag for shmget. */ -+#define SHM_R 0400 /* or S_IRUGO from */ -+#define SHM_W 0200 /* or S_IWUGO from */ -+ -+/* Flags for `shmat'. */ -+#define SHM_RDONLY 010000 /* attach read-only else read-write */ -+#define SHM_RND 020000 /* round attach address to SHMLBA */ -+#define SHM_REMAP 040000 /* take-over region on attach */ -+#define SHM_EXEC 0100000 /* execution access */ -+ -+/* Commands for `shmctl'. */ -+#define SHM_LOCK 11 /* lock segment (root only) */ -+#define SHM_UNLOCK 12 /* unlock segment (root only) */ -+ -+__BEGIN_DECLS -+ -+/* Segment low boundary address multiple. */ -+#define SHMLBA (__getpagesize () << 2) -+extern int __getpagesize (void) __THROW __attribute__ ((__const__)); -+ -+ -+/* Type to count number of attaches. */ -+typedef unsigned long int shmatt_t; -+ -+/* Data structure describing a shared memory segment. */ -+struct shmid_ds -+ { -+ struct ipc_perm shm_perm; /* operation permission struct */ -+ size_t shm_segsz; /* size of segment in bytes */ -+ __time_t shm_atime; /* time of last shmat() */ -+#if __WORDSIZE == 32 -+ unsigned long int __glibc_reserved1; -+#endif -+ __time_t shm_dtime; /* time of last shmdt() */ -+#if __WORDSIZE == 32 -+ unsigned long int __glibc_reserved2; -+#endif -+ __time_t shm_ctime; /* time of last change by shmctl() */ -+#if __WORDSIZE == 32 -+ unsigned long int __glibc_reserved3; -+#endif -+ __pid_t shm_cpid; /* pid of creator */ -+ __pid_t shm_lpid; /* pid of last shmop */ -+ shmatt_t shm_nattch; /* number of current attaches */ -+ unsigned long int __glibc_reserved4; -+ unsigned long int __glibc_reserved5; -+ }; -+ -+#ifdef __USE_MISC -+ -+/* ipcs ctl commands */ -+# define SHM_STAT 13 -+# define SHM_INFO 14 -+# define SHM_STAT_ANY 15 -+ -+/* shm_mode upper byte flags */ -+# define SHM_DEST 01000 /* segment will be destroyed on last detach */ -+# define SHM_LOCKED 02000 /* segment will not be swapped */ -+# define SHM_HUGETLB 04000 /* segment is mapped via hugetlb */ -+# define SHM_NORESERVE 010000 /* don't check for reservations */ -+ -+struct shminfo -+ { -+ unsigned long int shmmax; -+ unsigned long int shmmin; -+ unsigned long int shmmni; -+ unsigned long int shmseg; -+ unsigned long int shmall; -+ unsigned long int __glibc_reserved1; -+ unsigned long int __glibc_reserved2; -+ unsigned long int __glibc_reserved3; -+ unsigned long int __glibc_reserved4; -+ }; -+ -+struct shm_info -+ { -+ int used_ids; -+ unsigned long int shm_tot; /* total allocated shm */ -+ unsigned long int shm_rss; /* total resident shm */ -+ unsigned long int shm_swp; /* total swapped shm */ -+ unsigned long int swap_attempts; -+ unsigned long int swap_successes; -+ }; -+ -+#endif /* __USE_MISC */ -+ -+__END_DECLS -diff --git a/sysdeps/unix/sysv/linux/loongarch/bits/sigcontext.h b/sysdeps/unix/sysv/linux/loongarch/bits/sigcontext.h -new file mode 100644 -index 00000000..0f925b4c ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/bits/sigcontext.h -@@ -0,0 +1,47 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * Copyright (C) 1996, 1997, 1999 by Ralf Baechle -+ * Copyright (C) 1999 Silicon Graphics, Inc. -+ */ -+#ifndef _BITS_SIGCONTEXT_H -+#define _BITS_SIGCONTEXT_H -+ -+/* -+ * Keep this struct definition in sync with the sigcontext fragment -+ * in arch/mips/kernel/asm-offsets.c -+ * -+ * Warning: this structure illdefined with sc_badvaddr being just an unsigned -+ * int so it was changed to unsigned long in 2.6.0-test1. This may break -+ * binary compatibility - no prisoners. -+ * DSP ASE in 2.6.12-rc4. Turn sc_mdhi and sc_mdlo into an array of four -+ * entries, add sc_dsp and sc_reserved for padding. No prisoners. -+ */ -+ -+#define FPU_REG_WIDTH 256 -+#define FPU_ALIGN __attribute__((aligned(32))) -+ -+struct sigcontext { -+ unsigned long long sc_pc; -+ unsigned long long sc_regs[32]; -+ unsigned int sc_flags; -+ -+ unsigned int sc_fcsr; -+ unsigned int sc_vcsr; -+ unsigned long long sc_fcc; -+ -+ unsigned long long sc_scr[4]; -+ -+ union { -+ unsigned int val32[FPU_REG_WIDTH / 32]; -+ unsigned long long val64[FPU_REG_WIDTH / 64]; -+ } sc_fpregs[32] FPU_ALIGN; -+ unsigned char sc_reserved[4096] __attribute__((__aligned__(16))); -+ -+}; -+ -+ -+#endif /* _BITS_SIGCONTEXT_H */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/bits/signum.h b/sysdeps/unix/sysv/linux/loongarch/bits/signum.h -new file mode 100644 -index 00000000..3cad0b19 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/bits/signum.h -@@ -0,0 +1,58 @@ -+/* Signal number definitions. Linux version. -+ Copyright (C) 1995-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#ifndef _BITS_SIGNUM_H -+#define _BITS_SIGNUM_H 1 -+ -+#ifndef _SIGNAL_H -+#error "Never include directly; use instead." -+#endif -+ -+#include -+ -+/* Adjustments and additions to the signal number constants for -+ most Linux systems. */ -+ -+#define SIGSTKFLT 16 /* Stack fault (obsolete). */ -+#define SIGPWR 30 /* Power failure imminent. */ -+ -+#undef SIGBUS -+#define SIGBUS 7 -+#undef SIGUSR1 -+#define SIGUSR1 10 -+#undef SIGUSR2 -+#define SIGUSR2 12 -+#undef SIGCHLD -+#define SIGCHLD 17 -+#undef SIGCONT -+#define SIGCONT 18 -+#undef SIGSTOP -+#define SIGSTOP 19 -+#undef SIGTSTP -+#define SIGTSTP 20 -+#undef SIGURG -+#define SIGURG 23 -+#undef SIGPOLL -+#define SIGPOLL 29 -+#undef SIGSYS -+#define SIGSYS 31 -+ -+#undef __SIGRTMAX -+#define __SIGRTMAX 127 -+ -+#endif /* included. */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/clone.S b/sysdeps/unix/sysv/linux/loongarch/clone.S -new file mode 100644 -index 00000000..f0fc566e ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/clone.S -@@ -0,0 +1,98 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+/* clone() is even more special than fork() as it mucks with stacks -+ and invokes a function in the right context after its all over. */ -+ -+#include -+#include -+#define _ERRNO_H 1 -+#include -+#include -+#include "tcb-offsets.h" -+ -+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, -+ void *parent_tidptr, void *tls, void *child_tidptr) */ -+ -+ENTRY (__clone) -+ -+ /* Align stack to 16 or 8 bytes per the ABI. */ -+#if _LOONGARCH_SIM == _ABILP64 -+ addi.d t0, zero, -16 -+#elif _LOONGARCH_SIM == _ABILP32 -+ addi.w t0, zero, -8 -+#endif -+ and a1, a1, t0 -+ -+ /* Sanity check arguments. */ -+ beqz a0, L (invalid) /* No NULL function pointers. */ -+ beqz a1, L (invalid) /* No NULL stack pointers. */ -+ -+ addi.d a1, a1, -16 /* Reserve argument save space. */ -+ st.d a0, a1, 0 /* Save function pointer. */ -+ st.d a3, a1, SZREG /* Save argument pointer. */ -+ -+ /* The syscall expects the args to be in different slots. */ -+ or a0, a2, zero -+ or a2, a4, zero -+ or a3, a6, zero -+ or a4, a5, zero -+ -+ /* Do the system call. */ -+ li.d a7,__NR_clone -+ syscall 0 -+ -+ blt a0, zero ,L (error) -+ beqz a0,L (thread_start) -+ -+ /* Successful return from the parent. */ -+ ret -+ -+L (invalid): -+ li.d a0, -EINVAL -+ /* Something bad happened -- no child created. */ -+L (error): -+ b __syscall_error -+ END (__clone) -+ -+/* Load up the arguments to the function. Put this block of code in -+ its own function so that we can terminate the stack trace with our -+ debug info. */ -+ -+ENTRY (__thread_start) -+L (thread_start): -+ /* Terminate call stack by noting ra is undefined. Use a dummy -+ .cfi_label to force starting the FDE. */ -+ .cfi_label .Ldummy -+ cfi_undefined (1) -+ -+ /* Restore the arg for user's function. */ -+ ld.d a1, sp, 0 /* Function pointer. */ -+ ld.d a0, sp, SZREG /* Argument pointer. */ -+ -+ /* Call the user's function. */ -+ jirl ra, a1, 0 -+ -+ /* Call exit with the function's return value. */ -+ li.d a7, __NR_exit -+ syscall 0 -+ -+ END (__thread_start) -+ -+libc_hidden_def (__clone) -+weak_alias (__clone, clone) -diff --git a/sysdeps/unix/sysv/linux/loongarch/configure b/sysdeps/unix/sysv/linux/loongarch/configure -new file mode 100644 -index 00000000..a402323a ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/configure -@@ -0,0 +1,199 @@ -+# This file is generated from configure.ac by Autoconf. DO NOT EDIT! -+ # Local configure fragment for sysdeps/unix/sysv/linux/loongarch. -+ -+arch_minimum_kernel=4.15.0 -+ -+libc_cv_loongarch_int_abi=no -+ -+ -+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -+$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -+if ${ac_cv_path_GREP+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ if test -z "$GREP"; then -+ ac_path_GREP_found=false -+ # Loop through the user's path and test for each of PROGNAME-LIST -+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -+do -+ IFS=$as_save_IFS -+ test -z "$as_dir" && as_dir=. -+ for ac_prog in grep ggrep; do -+ for ac_exec_ext in '' $ac_executable_extensions; do -+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" -+ as_fn_executable_p "$ac_path_GREP" || continue -+# Check for GNU ac_path_GREP and select it if it is found. -+ # Check for GNU $ac_path_GREP -+case `"$ac_path_GREP" --version 2>&1` in -+*GNU*) -+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -+*) -+ ac_count=0 -+ $as_echo_n 0123456789 >"conftest.in" -+ while : -+ do -+ cat "conftest.in" "conftest.in" >"conftest.tmp" -+ mv "conftest.tmp" "conftest.in" -+ cp "conftest.in" "conftest.nl" -+ $as_echo 'GREP' >> "conftest.nl" -+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break -+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break -+ as_fn_arith $ac_count + 1 && ac_count=$as_val -+ if test $ac_count -gt ${ac_path_GREP_max-0}; then -+ # Best one so far, save it but keep looking for a better one -+ ac_cv_path_GREP="$ac_path_GREP" -+ ac_path_GREP_max=$ac_count -+ fi -+ # 10*(2^10) chars as input seems more than enough -+ test $ac_count -gt 10 && break -+ done -+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -+esac -+ -+ $ac_path_GREP_found && break 3 -+ done -+ done -+ done -+IFS=$as_save_IFS -+ if test -z "$ac_cv_path_GREP"; then -+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 -+ fi -+else -+ ac_cv_path_GREP=$GREP -+fi -+ -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -+$as_echo "$ac_cv_path_GREP" >&6; } -+ GREP="$ac_cv_path_GREP" -+ -+ -+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -+$as_echo_n "checking for egrep... " >&6; } -+if ${ac_cv_path_EGREP+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 -+ then ac_cv_path_EGREP="$GREP -E" -+ else -+ if test -z "$EGREP"; then -+ ac_path_EGREP_found=false -+ # Loop through the user's path and test for each of PROGNAME-LIST -+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -+do -+ IFS=$as_save_IFS -+ test -z "$as_dir" && as_dir=. -+ for ac_prog in egrep; do -+ for ac_exec_ext in '' $ac_executable_extensions; do -+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" -+ as_fn_executable_p "$ac_path_EGREP" || continue -+# Check for GNU ac_path_EGREP and select it if it is found. -+ # Check for GNU $ac_path_EGREP -+case `"$ac_path_EGREP" --version 2>&1` in -+*GNU*) -+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -+*) -+ ac_count=0 -+ $as_echo_n 0123456789 >"conftest.in" -+ while : -+ do -+ cat "conftest.in" "conftest.in" >"conftest.tmp" -+ mv "conftest.tmp" "conftest.in" -+ cp "conftest.in" "conftest.nl" -+ $as_echo 'EGREP' >> "conftest.nl" -+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break -+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break -+ as_fn_arith $ac_count + 1 && ac_count=$as_val -+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then -+ # Best one so far, save it but keep looking for a better one -+ ac_cv_path_EGREP="$ac_path_EGREP" -+ ac_path_EGREP_max=$ac_count -+ fi -+ # 10*(2^10) chars as input seems more than enough -+ test $ac_count -gt 10 && break -+ done -+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -+esac -+ -+ $ac_path_EGREP_found && break 3 -+ done -+ done -+ done -+IFS=$as_save_IFS -+ if test -z "$ac_cv_path_EGREP"; then -+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 -+ fi -+else -+ ac_cv_path_EGREP=$EGREP -+fi -+ -+ fi -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -+$as_echo "$ac_cv_path_EGREP" >&6; } -+ EGREP="$ac_cv_path_EGREP" -+ -+ -+cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+__SIZEOF_INT__ __SIZEOF_LONG__ __SIZEOF_POINTER__ -+ -+_ACEOF -+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | -+ $EGREP "4 4 4" >/dev/null 2>&1; then : -+ libc_cv_loongarch_int_abi=lp32 -+fi -+rm -f conftest* -+ -+cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+__SIZEOF_INT__ __SIZEOF_LONG__ __SIZEOF_POINTER__ -+ -+_ACEOF -+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | -+ $EGREP "4 8 8" >/dev/null 2>&1; then : -+ libc_cv_loongarch_int_abi=lp64 -+fi -+rm -f conftest* -+ -+if test $libc_cv_loongarch_int_abi = no; then -+ as_fn_error $? "Unable to determine integer ABI" "$LINENO" 5 -+fi -+ -+config_vars="$config_vars -+default-abi = $libc_cv_loongarch_int_abi" -+ -+case $libc_cv_loongarch_int_abi in -+lp32) -+ test -n "$libc_cv_slibdir" || -+case "$prefix" in -+/usr | /usr/) -+ libc_cv_slibdir='/lib32' -+ libc_cv_rtlddir='/lib32' -+ if test "$libdir" = '${exec_prefix}/lib'; then -+ libdir='${exec_prefix}/lib32'; -+ # Locale data can be shared between 32-bit and 64-bit libraries. -+ libc_cv_complocaledir='${exec_prefix}/lib/locale' -+ fi -+ ;; -+esac -+ ;; -+lp64) -+ test -n "$libc_cv_slibdir" || -+case "$prefix" in -+/usr | /usr/) -+ libc_cv_slibdir='/lib64' -+ libc_cv_rtlddir='/lib64' -+ if test "$libdir" = '${exec_prefix}/lib'; then -+ libdir='${exec_prefix}/lib64'; -+ # Locale data can be shared between 32-bit and 64-bit libraries. -+ libc_cv_complocaledir='${exec_prefix}/lib/locale' -+ fi -+ ;; -+esac -+ ;; -+esac -+ -+ldd_rewrite_script=sysdeps/unix/sysv/linux/loongarch/ldd-rewrite.sed -diff --git a/sysdeps/unix/sysv/linux/loongarch/configure.ac b/sysdeps/unix/sysv/linux/loongarch/configure.ac -new file mode 100644 -index 00000000..fef4f4d2 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/configure.ac -@@ -0,0 +1,27 @@ -+sinclude(./aclocal.m4)dnl Autoconf lossage -+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory. -+# Local configure fragment for sysdeps/unix/sysv/linux/loongarch. -+ -+arch_minimum_kernel=4.15.0 -+ -+libc_cv_loongarch_int_abi=no -+AC_EGREP_CPP(4 4 4, [__SIZEOF_INT__ __SIZEOF_LONG__ __SIZEOF_POINTER__ -+ ], libc_cv_loongarch_int_abi=lp32) -+AC_EGREP_CPP(4 8 8, [__SIZEOF_INT__ __SIZEOF_LONG__ __SIZEOF_POINTER__ -+ ], libc_cv_loongarch_int_abi=lp64) -+if test $libc_cv_loongarch_int_abi = no; then -+ AC_MSG_ERROR([Unable to determine integer ABI]) -+fi -+ -+LIBC_CONFIG_VAR([default-abi], [$libc_cv_loongarch_int_abi]) -+ -+case $libc_cv_loongarch_int_abi in -+lp32) -+ LIBC_SLIBDIR_RTLDDIR([lib32], [lib32]) -+ ;; -+lp64) -+ LIBC_SLIBDIR_RTLDDIR([lib64], [lib]) -+ ;; -+esac -+ -+ldd_rewrite_script=sysdeps/unix/sysv/linux/loongarch/ldd-rewrite.sed -diff --git a/sysdeps/unix/sysv/linux/loongarch/dl-static.c b/sysdeps/unix/sysv/linux/loongarch/dl-static.c -new file mode 100644 -index 00000000..12b030f0 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/dl-static.c -@@ -0,0 +1,84 @@ -+/* Copyright (C) 2020-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 -+ -+#ifdef SHARED -+ -+void -+_dl_var_init (void *array[]) -+{ -+ /* It has to match "variables" below. */ -+ enum -+ { -+ DL_PAGESIZE = 0 -+ }; -+ -+ GLRO(dl_pagesize) = *((size_t *) array[DL_PAGESIZE]); -+} -+ -+#else -+ -+static void *variables[] = -+{ -+ &GLRO(dl_pagesize) -+}; -+ -+static void -+_dl_unprotect_relro (struct link_map *l) -+{ -+ ElfW(Addr) start = ((l->l_addr + l->l_relro_addr) -+ & ~(GLRO(dl_pagesize) - 1)); -+ ElfW(Addr) end = ((l->l_addr + l->l_relro_addr + l->l_relro_size) -+ & ~(GLRO(dl_pagesize) - 1)); -+ -+ if (start != end) -+ __mprotect ((void *) start, end - start, PROT_READ | PROT_WRITE); -+} -+ -+void -+_dl_static_init (struct link_map *l) -+{ -+ struct link_map *rtld_map = l; -+ struct r_scope_elem **scope; -+ const ElfW(Sym) *ref = NULL; -+ lookup_t loadbase; -+ void (*f) (void *[]); -+ size_t i; -+ -+ loadbase = _dl_lookup_symbol_x ("_dl_var_init", l, &ref, l->l_local_scope, -+ NULL, 0, 1, NULL); -+ -+ for (scope = l->l_local_scope; *scope != NULL; scope++) -+ for (i = 0; i < (*scope)->r_nlist; i++) -+ if ((*scope)->r_list[i] == loadbase) -+ { -+ rtld_map = (*scope)->r_list[i]; -+ break; -+ } -+ -+ if (ref != NULL) -+ { -+ f = (void (*) (void *[])) DL_SYMBOL_ADDRESS (loadbase, ref); -+ _dl_unprotect_relro (rtld_map); -+ f (variables); -+ _dl_protect_relro (rtld_map); -+ } -+} -+ -+#endif -diff --git a/sysdeps/unix/sysv/linux/loongarch/getcontext.S b/sysdeps/unix/sysv/linux/loongarch/getcontext.S -new file mode 100644 -index 00000000..9c28d958 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/getcontext.S -@@ -0,0 +1,72 @@ -+/* Save current context. -+ Copyright (C) 2009-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#include "ucontext-macros.h" -+ -+/* int getcontext (ucontext_t *ucp) */ -+ -+ .text -+LEAF (__getcontext) -+ SAVE_INT_REG (ra, 1, a0) -+ SAVE_INT_REG (sp, 3, a0) -+ SAVE_INT_REG (zero, 4, a0) /* return 0 by overwriting a0. */ -+ SAVE_INT_REG (x, 21, a0) -+ SAVE_INT_REG (fp, 22, a0) -+ SAVE_INT_REG (s0, 23, a0) -+ SAVE_INT_REG (s1, 24, a0) -+ SAVE_INT_REG (s2, 25, a0) -+ SAVE_INT_REG (s3, 26, a0) -+ SAVE_INT_REG (s4, 27, a0) -+ SAVE_INT_REG (s5, 28, a0) -+ SAVE_INT_REG (s6, 29, a0) -+ SAVE_INT_REG (s7, 30, a0) -+ SAVE_INT_REG (s8, 31, a0) -+ st.d ra, a0, MCONTEXT_PC -+ -+#ifndef __loongarch_soft_float -+ movfcsr2gr a1, $r0 -+ -+ SAVE_FP_REG (fs0, 24, a0) -+ SAVE_FP_REG (fs1, 25, a0) -+ SAVE_FP_REG (fs2, 26, a0) -+ SAVE_FP_REG (fs3, 27, a0) -+ SAVE_FP_REG (fs4, 28, a0) -+ SAVE_FP_REG (fs5, 29, a0) -+ SAVE_FP_REG (fs6, 30, a0) -+ SAVE_FP_REG (fs7, 31, a0) -+ -+ st.w a1, a0, MCONTEXT_FCSR -+#endif /* __loongarch_soft_float */ -+ -+/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ -+ li.d a3, _NSIG8 -+ addi.d a2, a0, UCONTEXT_SIGMASK -+ ori a1, zero,0 -+ li.d a0, SIG_BLOCK -+ -+ li.d a7, SYS_ify (rt_sigprocmask) -+ syscall 0 -+ blt a0, zero, 99f -+ -+ jirl $r0, $r1, 0 -+ -+99: b __syscall_error -+ -+PSEUDO_END (__getcontext) -+ -+weak_alias (__getcontext, getcontext) -diff --git a/sysdeps/unix/sysv/linux/loongarch/getpid.c b/sysdeps/unix/sysv/linux/loongarch/getpid.c -new file mode 100644 -index 00000000..5b4edb2b ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/getpid.c -@@ -0,0 +1,54 @@ -+/* getpid - get the pid. Linux/Loongarch version. -+ Copyright (C) 2015-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+ -+#ifdef SHARED -+# include -+# include -+ -+static pid_t -+__getpid_syscall (void) -+{ -+ return INLINE_SYSCALL (getpid, 0); -+} -+ -+# ifndef __getpid_type -+# define __getpid_type __getpid -+# endif -+ -+# undef INIT_ARCH -+# define INIT_ARCH() PREPARE_VERSION_KNOWN (linux26, LINUX_2_6) -+libc_ifunc_hidden (__getpid_type, __getpid, (_dl_vdso_vsym ("__vdso_getpid", &linux26) ?: &__getpid_syscall)) -+libc_hidden_def (__getpid) -+ -+#else -+ -+# include -+# include -+ -+pid_t -+__getpid (void) -+{ -+ return INLINE_SYSCALL (getpid, 0); -+} -+libc_hidden_def (__getpid); -+ -+#endif -+weak_alias (__getpid, getpid) -+libc_hidden_weak (getpid) -diff --git a/sysdeps/unix/sysv/linux/loongarch/gettimeofday.c b/sysdeps/unix/sysv/linux/loongarch/gettimeofday.c -new file mode 100644 -index 00000000..902b1a5d ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/gettimeofday.c -@@ -0,0 +1,58 @@ -+/* gettimeofday - get the time. Linux/LoongArch version. -+ Copyright (C) 2015-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+ -+#ifdef SHARED -+ -+# include -+# include -+ -+static int -+__gettimeofday_syscall (struct timeval *tv, struct timezone *tz) -+{ -+ return INLINE_SYSCALL (gettimeofday, 2, tv, tz); -+} -+ -+# ifndef __gettimeofday_type -+# define __gettimeofday_type __gettimeofday -+# endif -+ -+# undef INIT_ARCH -+# define INIT_ARCH() PREPARE_VERSION_KNOWN (linux26, LINUX_2_6) -+/* If the vDSO is not available we fall back to syscall. */ -+libc_ifunc_hidden (__gettimeofday_type, __gettimeofday, -+ (_dl_vdso_vsym ("__vdso_gettimeofday", &linux26) -+ ?: &__gettimeofday_syscall)) -+libc_hidden_def (__gettimeofday) -+ -+#else -+ -+# include -+# include -+ -+int -+__gettimeofday (struct timeval *tv, struct timezone *tz) -+{ -+ return INLINE_SYSCALL (gettimeofday, 2, tv, tz); -+} -+libc_hidden_def (__gettimeofday) -+ -+#endif -+weak_alias (__gettimeofday, gettimeofday) -+libc_hidden_weak (gettimeofday) -diff --git a/sysdeps/unix/sysv/linux/loongarch/getuid.c b/sysdeps/unix/sysv/linux/loongarch/getuid.c -new file mode 100644 -index 00000000..4b3f95eb ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/getuid.c -@@ -0,0 +1,60 @@ -+/* getuid - get the uid. Linux/Loongarch version. -+ Copyright (C) 2015-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+ -+#ifdef SHARED -+ -+# include -+# include -+ -+libc_hidden_proto (getuid) -+ -+extern __uid_t __getuid (void); -+libc_hidden_proto (__getuid) -+ -+static uid_t -+__getuid_syscall(void) -+{ -+ return INLINE_SYSCALL (getuid, 0); -+} -+ -+# ifndef __getuid_type -+# define __getuid_type __getuid -+# endif -+ -+# undef INIT_ARCH -+# define INIT_ARCH() PREPARE_VERSION_KNOWN (linux26, LINUX_2_6) -+libc_ifunc_hidden (__getuid_type, __getuid, (_dl_vdso_vsym ("__vdso_getuid", &linux26) ?: &__getuid_syscall)) -+libc_hidden_def (__getuid) -+ -+#else -+ -+# include -+# include -+ -+uid_t -+__getuid(void) -+{ -+ return INLINE_SYSCALL (getuid, 0); -+} -+libc_hidden_def (__getuid) -+ -+#endif -+weak_alias (__getuid, getuid) -+libc_hidden_weak (getuid) -diff --git a/sysdeps/unix/sysv/linux/loongarch/init-first.c b/sysdeps/unix/sysv/linux/loongarch/init-first.c -new file mode 100644 -index 00000000..5185a831 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/init-first.c -@@ -0,0 +1,57 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+#ifdef SHARED -+# include -+# include -+ -+long int (*VDSO_SYMBOL (getcpu)) (unsigned int *, unsigned int *, void *) -+ attribute_hidden; -+long int (*VDSO_SYMBOL (gettimeofday)) (struct timeval *, void *) -+ attribute_hidden; -+long int (*VDSO_SYMBOL (clock_gettime)) (clockid_t, struct timespec *) -+ attribute_hidden; -+long int (*VDSO_SYMBOL (clock_getres)) (clockid_t, struct timespec *) -+ attribute_hidden; -+ -+static inline void -+_libc_vdso_platform_setup (void) -+{ -+ PREPARE_VERSION_KNOWN (linux_version, LINUX_2_6); -+ -+ void *p = _dl_vdso_vsym ("__vdso_getcpu", &linux_version); -+ PTR_MANGLE (p); -+ VDSO_SYMBOL (getcpu) = p; -+ -+ p = _dl_vdso_vsym ("__vdso_gettimeofday", &linux_version); -+ PTR_MANGLE (p); -+ VDSO_SYMBOL (gettimeofday) = p; -+ -+ p = _dl_vdso_vsym ("__vdso_clock_gettime", &linux_version); -+ PTR_MANGLE (p); -+ VDSO_SYMBOL (clock_gettime) = p; -+ -+ p = _dl_vdso_vsym ("__vdso_clock_getres", &linux_version); -+ PTR_MANGLE (p); -+ VDSO_SYMBOL (clock_getres) = p; -+} -+ -+# define VDSO_SETUP _libc_vdso_platform_setup -+#endif -+ -+#include -diff --git a/sysdeps/unix/sysv/linux/loongarch/ipc_priv.h b/sysdeps/unix/sysv/linux/loongarch/ipc_priv.h -new file mode 100644 -index 00000000..51583429 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/ipc_priv.h -@@ -0,0 +1,21 @@ -+/* Old SysV permission definition for Linux. LoongArch version. -+ Copyright (C) 2020 Loongson Technology, 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 /* For __key_t */ -+ -+#define __IPC_64 0x0 -diff --git a/sysdeps/unix/sysv/linux/loongarch/kernel-features.h b/sysdeps/unix/sysv/linux/loongarch/kernel-features.h -new file mode 100644 -index 00000000..c87c7967 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/kernel-features.h -@@ -0,0 +1,24 @@ -+/* Copyright (C) 2020-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_next -+ -+/* No support for PI mutexes or robust futexes before 4.20. */ -+#if __LINUX_KERNEL_VERSION < 0x041400 -+# undef __ASSUME_SET_ROBUST_LIST -+#endif -diff --git a/sysdeps/unix/sysv/linux/loongarch/ldd-rewrite.sed b/sysdeps/unix/sysv/linux/loongarch/ldd-rewrite.sed -new file mode 100644 -index 00000000..131c5f14 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/ldd-rewrite.sed -@@ -0,0 +1 @@ -+s_^\(RTLDLIST=\)\(.*lib/\)\(ld-linux\)-\(loongarch64\)-\(lp64\)\(d*\)\(\.so\.[0-9.]*\)_\1"\2\3-\4-\5\7 \2\3-\4-\5d\7"_ -diff --git a/sysdeps/unix/sysv/linux/loongarch/ldsodefs.h b/sysdeps/unix/sysv/linux/loongarch/ldsodefs.h -new file mode 100644 -index 00000000..c0fc7046 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/ldsodefs.h -@@ -0,0 +1,32 @@ -+/* Copyright (C) 2020-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 _LDSODEFS_H -+ -+/* Get the real definitions. */ -+#include_next -+ -+/* Now define our stuff. */ -+ -+/* We need special support to initialize DSO loaded for statically linked -+ binaries. */ -+extern void _dl_static_init (struct link_map *map); -+#undef DL_STATIC_INIT -+#define DL_STATIC_INIT(map) _dl_static_init (map) -+ -+#endif /* ldsodefs.h */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/libc-vdso.h b/sysdeps/unix/sysv/linux/loongarch/libc-vdso.h -new file mode 100644 -index 00000000..658c27a5 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/libc-vdso.h -@@ -0,0 +1,37 @@ -+/* Copyright (C) 2020-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 _LIBC_VDSO_H -+#define _LIBC_VDSO_H -+ -+#ifdef SHARED -+ -+# include -+ -+extern long int (*VDSO_SYMBOL (getcpu)) (unsigned int *, unsigned int *, void *) -+ attribute_hidden; -+extern long int (*VDSO_SYMBOL (gettimeofday)) (struct timeval *, void *) -+ attribute_hidden; -+extern long int (*VDSO_SYMBOL (clock_gettime)) (clockid_t, struct timespec *) -+ attribute_hidden; -+extern long int (*VDSO_SYMBOL (clock_getres)) (clockid_t, struct timespec *) -+ attribute_hidden; -+ -+#endif -+ -+#endif /* _LIBC_VDSO_H */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/localplt.data b/sysdeps/unix/sysv/linux/loongarch/localplt.data -new file mode 100644 -index 00000000..0ed8650b ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/localplt.data -@@ -0,0 +1,13 @@ -+# See scripts/check-localplt.awk for how this file is processed. -+# PLT use is required for the malloc family and for matherr because -+# users can define their own functions and have library internals call them. -+libc.so: calloc -+libc.so: free -+libc.so: malloc -+libc.so: memalign -+libc.so: realloc -+# The TLS-enabled version of these functions is interposed from libc.so. -+ld.so: _dl_signal_error -+ld.so: _dl_catch_error -+ld.so: _dl_signal_exception -+ld.so: _dl_catch_exception -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/Implies b/sysdeps/unix/sysv/linux/loongarch/lp64/Implies -new file mode 100644 -index 00000000..117c2b8e ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/Implies -@@ -0,0 +1,3 @@ -+unix/sysv/linux/loongarch -+unix/sysv/linux/generic -+unix/sysv/linux/wordsize-64 -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/c++-types.data b/sysdeps/unix/sysv/linux/loongarch/lp64/c++-types.data -new file mode 100644 -index 00000000..ac925ccb ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/c++-types.data -@@ -0,0 +1,67 @@ -+blkcnt64_t:l -+blkcnt_t:l -+blksize_t:i -+caddr_t:Pc -+clockid_t:i -+clock_t:l -+daddr_t:i -+dev_t:m -+fd_mask:l -+fsblkcnt64_t:m -+fsblkcnt_t:m -+fsfilcnt64_t:m -+fsfilcnt_t:m -+fsid_t:8__fsid_t -+gid_t:j -+id_t:j -+ino64_t:m -+ino_t:m -+int16_t:s -+int32_t:i -+int64_t:l -+int8_t:a -+intptr_t:l -+key_t:i -+loff_t:l -+mode_t:j -+nlink_t:j -+off64_t:l -+off_t:l -+pid_t:i -+pthread_attr_t:14pthread_attr_t -+pthread_barrier_t:17pthread_barrier_t -+pthread_barrierattr_t:21pthread_barrierattr_t -+pthread_cond_t:14pthread_cond_t -+pthread_condattr_t:18pthread_condattr_t -+pthread_key_t:j -+pthread_mutex_t:15pthread_mutex_t -+pthread_mutexattr_t:19pthread_mutexattr_t -+pthread_once_t:i -+pthread_rwlock_t:16pthread_rwlock_t -+pthread_rwlockattr_t:20pthread_rwlockattr_t -+pthread_spinlock_t:i -+pthread_t:m -+quad_t:l -+register_t:l -+rlim64_t:m -+rlim_t:m -+sigset_t:10__sigset_t -+size_t:m -+socklen_t:j -+ssize_t:l -+suseconds_t:l -+time_t:l -+u_char:h -+uid_t:j -+uint:j -+u_int:j -+u_int16_t:t -+u_int32_t:j -+u_int64_t:m -+u_int8_t:h -+ulong:m -+u_long:m -+u_quad_t:m -+useconds_t:j -+ushort:t -+u_short:t -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/jmp_buf-macros.h b/sysdeps/unix/sysv/linux/loongarch/lp64/jmp_buf-macros.h -new file mode 100644 -index 00000000..e1c96e67 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/jmp_buf-macros.h -@@ -0,0 +1,41 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+/* Produced by this program: -+ -+ #include -+ #include -+ #include -+ #include -+ -+ int main (int argc, char **argv) -+ { -+ printf ("#define JMP_BUF_SIZE %d\n", sizeof (jmp_buf)); -+ printf ("#define JMP_BUF_ALIGN %d\n", __alignof__ (jmp_buf)); -+ printf ("#define SIGJMP_BUF_SIZE %d\n", sizeof (sigjmp_buf)); -+ printf ("#define SIGJMP_BUF_ALIGN %d\n", __alignof__ (sigjmp_buf)); -+ printf ("#define MASK_WAS_SAVED_OFFSET %d\n", offsetof (struct __jmp_buf_tag, __mask_was_saved)); -+ printf ("#define SAVED_MASK_OFFSET %d\n", offsetof (struct __jmp_buf_tag, __saved_mask)); -+ } */ -+ -+# define JMP_BUF_SIZE 304 -+# define JMP_BUF_ALIGN 8 -+# define SIGJMP_BUF_SIZE 304 -+# define SIGJMP_BUF_ALIGN 8 -+# define MASK_WAS_SAVED_OFFSET 168 -+# define SAVED_MASK_OFFSET 176 -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/ld.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/ld.abilist -new file mode 100644 -index 00000000..845f356c ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/ld.abilist -@@ -0,0 +1,5 @@ -+GLIBC_2.27 __libc_stack_end D 0x8 -+GLIBC_2.27 __stack_chk_guard D 0x8 -+GLIBC_2.27 __tls_get_addr F -+GLIBC_2.27 _dl_mcount F -+GLIBC_2.27 _r_debug D 0x28 -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libBrokenLocale.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libBrokenLocale.abilist -new file mode 100644 -index 00000000..18968d3c ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libBrokenLocale.abilist -@@ -0,0 +1 @@ -+GLIBC_2.27 __ctype_get_mb_cur_max F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libanl.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libanl.abilist -new file mode 100644 -index 00000000..711fc87c ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libanl.abilist -@@ -0,0 +1,4 @@ -+GLIBC_2.27 gai_cancel F -+GLIBC_2.27 gai_error F -+GLIBC_2.27 gai_suspend F -+GLIBC_2.27 getaddrinfo_a F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist -new file mode 100644 -index 00000000..4d8733f2 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist -@@ -0,0 +1,2101 @@ -+GLIBC_2.27 _Exit F -+GLIBC_2.27 _IO_2_1_stderr_ D 0xe0 -+GLIBC_2.27 _IO_2_1_stdin_ D 0xe0 -+GLIBC_2.27 _IO_2_1_stdout_ D 0xe0 -+GLIBC_2.27 _IO_adjust_column F -+GLIBC_2.27 _IO_adjust_wcolumn F -+GLIBC_2.27 _IO_default_doallocate F -+GLIBC_2.27 _IO_default_finish F -+GLIBC_2.27 _IO_default_pbackfail F -+GLIBC_2.27 _IO_default_uflow F -+GLIBC_2.27 _IO_default_xsgetn F -+GLIBC_2.27 _IO_default_xsputn F -+GLIBC_2.27 _IO_do_write F -+GLIBC_2.27 _IO_doallocbuf F -+GLIBC_2.27 _IO_fclose F -+GLIBC_2.27 _IO_fdopen F -+GLIBC_2.27 _IO_feof F -+GLIBC_2.27 _IO_ferror F -+GLIBC_2.27 _IO_fflush F -+GLIBC_2.27 _IO_fgetpos F -+GLIBC_2.27 _IO_fgetpos64 F -+GLIBC_2.27 _IO_fgets F -+GLIBC_2.27 _IO_file_attach F -+GLIBC_2.27 _IO_file_close F -+GLIBC_2.27 _IO_file_close_it F -+GLIBC_2.27 _IO_file_doallocate F -+GLIBC_2.27 _IO_file_finish F -+GLIBC_2.27 _IO_file_fopen F -+GLIBC_2.27 _IO_file_init F -+GLIBC_2.27 _IO_file_jumps D 0xa8 -+GLIBC_2.27 _IO_file_open F -+GLIBC_2.27 _IO_file_overflow F -+GLIBC_2.27 _IO_file_read F -+GLIBC_2.27 _IO_file_seek F -+GLIBC_2.27 _IO_file_seekoff F -+GLIBC_2.27 _IO_file_setbuf F -+GLIBC_2.27 _IO_file_stat F -+GLIBC_2.27 _IO_file_sync F -+GLIBC_2.27 _IO_file_underflow F -+GLIBC_2.27 _IO_file_write F -+GLIBC_2.27 _IO_file_xsputn F -+GLIBC_2.27 _IO_flockfile F -+GLIBC_2.27 _IO_flush_all F -+GLIBC_2.27 _IO_flush_all_linebuffered F -+GLIBC_2.27 _IO_fopen F -+GLIBC_2.27 _IO_fprintf F -+GLIBC_2.27 _IO_fputs F -+GLIBC_2.27 _IO_fread F -+GLIBC_2.27 _IO_free_backup_area F -+GLIBC_2.27 _IO_free_wbackup_area F -+GLIBC_2.27 _IO_fsetpos F -+GLIBC_2.27 _IO_fsetpos64 F -+GLIBC_2.27 _IO_ftell F -+GLIBC_2.27 _IO_ftrylockfile F -+GLIBC_2.27 _IO_funlockfile F -+GLIBC_2.27 _IO_fwrite F -+GLIBC_2.27 _IO_getc F -+GLIBC_2.27 _IO_getline F -+GLIBC_2.27 _IO_getline_info F -+GLIBC_2.27 _IO_gets F -+GLIBC_2.27 _IO_init F -+GLIBC_2.27 _IO_init_marker F -+GLIBC_2.27 _IO_init_wmarker F -+GLIBC_2.27 _IO_iter_begin F -+GLIBC_2.27 _IO_iter_end F -+GLIBC_2.27 _IO_iter_file F -+GLIBC_2.27 _IO_iter_next F -+GLIBC_2.27 _IO_least_wmarker F -+GLIBC_2.27 _IO_link_in F -+GLIBC_2.27 _IO_list_all D 0x8 -+GLIBC_2.27 _IO_list_lock F -+GLIBC_2.27 _IO_list_resetlock F -+GLIBC_2.27 _IO_list_unlock F -+GLIBC_2.27 _IO_marker_delta F -+GLIBC_2.27 _IO_marker_difference F -+GLIBC_2.27 _IO_padn F -+GLIBC_2.27 _IO_peekc_locked F -+GLIBC_2.27 _IO_popen F -+GLIBC_2.27 _IO_printf F -+GLIBC_2.27 _IO_proc_close F -+GLIBC_2.27 _IO_proc_open F -+GLIBC_2.27 _IO_putc F -+GLIBC_2.27 _IO_puts F -+GLIBC_2.27 _IO_remove_marker F -+GLIBC_2.27 _IO_seekmark F -+GLIBC_2.27 _IO_seekoff F -+GLIBC_2.27 _IO_seekpos F -+GLIBC_2.27 _IO_seekwmark F -+GLIBC_2.27 _IO_setb F -+GLIBC_2.27 _IO_setbuffer F -+GLIBC_2.27 _IO_setvbuf F -+GLIBC_2.27 _IO_sgetn F -+GLIBC_2.27 _IO_sprintf F -+GLIBC_2.27 _IO_sputbackc F -+GLIBC_2.27 _IO_sputbackwc F -+GLIBC_2.27 _IO_sscanf F -+GLIBC_2.27 _IO_str_init_readonly F -+GLIBC_2.27 _IO_str_init_static F -+GLIBC_2.27 _IO_str_overflow F -+GLIBC_2.27 _IO_str_pbackfail F -+GLIBC_2.27 _IO_str_seekoff F -+GLIBC_2.27 _IO_str_underflow F -+GLIBC_2.27 _IO_sungetc F -+GLIBC_2.27 _IO_sungetwc F -+GLIBC_2.27 _IO_switch_to_get_mode F -+GLIBC_2.27 _IO_switch_to_main_wget_area F -+GLIBC_2.27 _IO_switch_to_wbackup_area F -+GLIBC_2.27 _IO_switch_to_wget_mode F -+GLIBC_2.27 _IO_un_link F -+GLIBC_2.27 _IO_ungetc F -+GLIBC_2.27 _IO_unsave_markers F -+GLIBC_2.27 _IO_unsave_wmarkers F -+GLIBC_2.27 _IO_vfprintf F -+GLIBC_2.27 _IO_vfscanf F -+GLIBC_2.27 _IO_vsprintf F -+GLIBC_2.27 _IO_wdefault_doallocate F -+GLIBC_2.27 _IO_wdefault_finish F -+GLIBC_2.27 _IO_wdefault_pbackfail F -+GLIBC_2.27 _IO_wdefault_uflow F -+GLIBC_2.27 _IO_wdefault_xsgetn F -+GLIBC_2.27 _IO_wdefault_xsputn F -+GLIBC_2.27 _IO_wdo_write F -+GLIBC_2.27 _IO_wdoallocbuf F -+GLIBC_2.27 _IO_wfile_jumps D 0xa8 -+GLIBC_2.27 _IO_wfile_overflow F -+GLIBC_2.27 _IO_wfile_seekoff F -+GLIBC_2.27 _IO_wfile_sync F -+GLIBC_2.27 _IO_wfile_underflow F -+GLIBC_2.27 _IO_wfile_xsputn F -+GLIBC_2.27 _IO_wmarker_delta F -+GLIBC_2.27 _IO_wsetb F -+GLIBC_2.27 ___brk_addr D 0x8 -+GLIBC_2.27 __adjtimex F -+GLIBC_2.27 __after_morecore_hook D 0x8 -+GLIBC_2.27 __argz_count F -+GLIBC_2.27 __argz_next F -+GLIBC_2.27 __argz_stringify F -+GLIBC_2.27 __asprintf F -+GLIBC_2.27 __asprintf_chk F -+GLIBC_2.27 __assert F -+GLIBC_2.27 __assert_fail F -+GLIBC_2.27 __assert_perror_fail F -+GLIBC_2.27 __backtrace F -+GLIBC_2.27 __backtrace_symbols F -+GLIBC_2.27 __backtrace_symbols_fd F -+GLIBC_2.27 __bsd_getpgrp F -+GLIBC_2.27 __bzero F -+GLIBC_2.27 __check_rhosts_file D 0x4 -+GLIBC_2.27 __chk_fail F -+GLIBC_2.27 __clone F -+GLIBC_2.27 __close F -+GLIBC_2.27 __cmsg_nxthdr F -+GLIBC_2.27 __confstr_chk F -+GLIBC_2.27 __connect F -+GLIBC_2.27 __ctype_b_loc F -+GLIBC_2.27 __ctype_get_mb_cur_max F -+GLIBC_2.27 __ctype_tolower_loc F -+GLIBC_2.27 __ctype_toupper_loc F -+GLIBC_2.27 __curbrk D 0x8 -+GLIBC_2.27 __cxa_at_quick_exit F -+GLIBC_2.27 __cxa_atexit F -+GLIBC_2.27 __cxa_finalize F -+GLIBC_2.27 __cxa_thread_atexit_impl F -+GLIBC_2.27 __cyg_profile_func_enter F -+GLIBC_2.27 __cyg_profile_func_exit F -+GLIBC_2.27 __daylight D 0x4 -+GLIBC_2.27 __dcgettext F -+GLIBC_2.27 __default_morecore F -+GLIBC_2.27 __dgettext F -+GLIBC_2.27 __dprintf_chk F -+GLIBC_2.27 __dup2 F -+GLIBC_2.27 __duplocale F -+GLIBC_2.27 __endmntent F -+GLIBC_2.27 __environ D 0x8 -+GLIBC_2.27 __errno_location F -+GLIBC_2.27 __explicit_bzero_chk F -+GLIBC_2.27 __fbufsize F -+GLIBC_2.27 __fcntl F -+GLIBC_2.27 __fdelt_chk F -+GLIBC_2.27 __fdelt_warn F -+GLIBC_2.27 __ffs F -+GLIBC_2.27 __fgets_chk F -+GLIBC_2.27 __fgets_unlocked_chk F -+GLIBC_2.27 __fgetws_chk F -+GLIBC_2.27 __fgetws_unlocked_chk F -+GLIBC_2.27 __finite F -+GLIBC_2.27 __finitef F -+GLIBC_2.27 __finitel F -+GLIBC_2.27 __flbf F -+GLIBC_2.27 __fork F -+GLIBC_2.27 __fpending F -+GLIBC_2.27 __fprintf_chk F -+GLIBC_2.27 __fpu_control D 0x4 -+GLIBC_2.27 __fpurge F -+GLIBC_2.27 __fread_chk F -+GLIBC_2.27 __fread_unlocked_chk F -+GLIBC_2.27 __freadable F -+GLIBC_2.27 __freading F -+GLIBC_2.27 __free_hook D 0x8 -+GLIBC_2.27 __freelocale F -+GLIBC_2.27 __fsetlocking F -+GLIBC_2.27 __fwprintf_chk F -+GLIBC_2.27 __fwritable F -+GLIBC_2.27 __fwriting F -+GLIBC_2.27 __fxstat F -+GLIBC_2.27 __fxstat64 F -+GLIBC_2.27 __fxstatat F -+GLIBC_2.27 __fxstatat64 F -+GLIBC_2.27 __getauxval F -+GLIBC_2.27 __getcwd_chk F -+GLIBC_2.27 __getdelim F -+GLIBC_2.27 __getdomainname_chk F -+GLIBC_2.27 __getgroups_chk F -+GLIBC_2.27 __gethostname_chk F -+GLIBC_2.27 __getlogin_r_chk F -+GLIBC_2.27 __getmntent_r F -+GLIBC_2.27 __getpagesize F -+GLIBC_2.27 __getpgid F -+GLIBC_2.27 __getpid F -+GLIBC_2.27 __gets_chk F -+GLIBC_2.27 __gettimeofday F -+GLIBC_2.27 __getwd_chk F -+GLIBC_2.27 __gmtime_r F -+GLIBC_2.27 __h_errno_location F -+GLIBC_2.27 __isalnum_l F -+GLIBC_2.27 __isalpha_l F -+GLIBC_2.27 __isascii_l F -+GLIBC_2.27 __isblank_l F -+GLIBC_2.27 __iscntrl_l F -+GLIBC_2.27 __isctype F -+GLIBC_2.27 __isdigit_l F -+GLIBC_2.27 __isgraph_l F -+GLIBC_2.27 __isinf F -+GLIBC_2.27 __isinff F -+GLIBC_2.27 __isinfl F -+GLIBC_2.27 __islower_l F -+GLIBC_2.27 __isnan F -+GLIBC_2.27 __isnanf F -+GLIBC_2.27 __isnanl F -+GLIBC_2.27 __isoc99_fscanf F -+GLIBC_2.27 __isoc99_fwscanf F -+GLIBC_2.27 __isoc99_scanf F -+GLIBC_2.27 __isoc99_sscanf F -+GLIBC_2.27 __isoc99_swscanf F -+GLIBC_2.27 __isoc99_vfscanf F -+GLIBC_2.27 __isoc99_vfwscanf F -+GLIBC_2.27 __isoc99_vscanf F -+GLIBC_2.27 __isoc99_vsscanf F -+GLIBC_2.27 __isoc99_vswscanf F -+GLIBC_2.27 __isoc99_vwscanf F -+GLIBC_2.27 __isoc99_wscanf F -+GLIBC_2.27 __isprint_l F -+GLIBC_2.27 __ispunct_l F -+GLIBC_2.27 __isspace_l F -+GLIBC_2.27 __isupper_l F -+GLIBC_2.27 __iswalnum_l F -+GLIBC_2.27 __iswalpha_l F -+GLIBC_2.27 __iswblank_l F -+GLIBC_2.27 __iswcntrl_l F -+GLIBC_2.27 __iswctype F -+GLIBC_2.27 __iswctype_l F -+GLIBC_2.27 __iswdigit_l F -+GLIBC_2.27 __iswgraph_l F -+GLIBC_2.27 __iswlower_l F -+GLIBC_2.27 __iswprint_l F -+GLIBC_2.27 __iswpunct_l F -+GLIBC_2.27 __iswspace_l F -+GLIBC_2.27 __iswupper_l F -+GLIBC_2.27 __iswxdigit_l F -+GLIBC_2.27 __isxdigit_l F -+GLIBC_2.27 __ivaliduser F -+GLIBC_2.27 __key_decryptsession_pk_LOCAL D 0x8 -+GLIBC_2.27 __key_encryptsession_pk_LOCAL D 0x8 -+GLIBC_2.27 __key_gendes_LOCAL D 0x8 -+GLIBC_2.27 __libc_allocate_rtsig F -+GLIBC_2.27 __libc_calloc F -+GLIBC_2.27 __libc_current_sigrtmax F -+GLIBC_2.27 __libc_current_sigrtmin F -+GLIBC_2.27 __libc_free F -+GLIBC_2.27 __libc_freeres F -+GLIBC_2.27 __libc_init_first F -+GLIBC_2.27 __libc_mallinfo F -+GLIBC_2.27 __libc_malloc F -+GLIBC_2.27 __libc_mallopt F -+GLIBC_2.27 __libc_memalign F -+GLIBC_2.27 __libc_pvalloc F -+GLIBC_2.27 __libc_realloc F -+GLIBC_2.27 __libc_sa_len F -+GLIBC_2.27 __libc_start_main F -+GLIBC_2.27 __libc_valloc F -+GLIBC_2.27 __longjmp_chk F -+GLIBC_2.27 __lseek F -+GLIBC_2.27 __lxstat F -+GLIBC_2.27 __lxstat64 F -+GLIBC_2.27 __malloc_hook D 0x8 -+GLIBC_2.27 __mbrlen F -+GLIBC_2.27 __mbrtowc F -+GLIBC_2.27 __mbsnrtowcs_chk F -+GLIBC_2.27 __mbsrtowcs_chk F -+GLIBC_2.27 __mbstowcs_chk F -+GLIBC_2.27 __memalign_hook D 0x8 -+GLIBC_2.27 __memcpy_chk F -+GLIBC_2.27 __memmove_chk F -+GLIBC_2.27 __mempcpy F -+GLIBC_2.27 __mempcpy_chk F -+GLIBC_2.27 __memset_chk F -+GLIBC_2.27 __monstartup F -+GLIBC_2.27 __morecore D 0x8 -+GLIBC_2.27 __nanosleep F -+GLIBC_2.27 __newlocale F -+GLIBC_2.27 __nl_langinfo_l F -+GLIBC_2.27 __nss_configure_lookup F -+GLIBC_2.27 __nss_database_lookup F -+GLIBC_2.27 __nss_hostname_digits_dots F -+GLIBC_2.27 __nss_next F -+GLIBC_2.27 __obstack_printf_chk F -+GLIBC_2.27 __obstack_vprintf_chk F -+GLIBC_2.27 __open F -+GLIBC_2.27 __open64 F -+GLIBC_2.27 __open64_2 F -+GLIBC_2.27 __open_2 F -+GLIBC_2.27 __openat64_2 F -+GLIBC_2.27 __openat_2 F -+GLIBC_2.27 __overflow F -+GLIBC_2.27 __pipe F -+GLIBC_2.27 __poll F -+GLIBC_2.27 __poll_chk F -+GLIBC_2.27 __posix_getopt F -+GLIBC_2.27 __ppoll_chk F -+GLIBC_2.27 __pread64 F -+GLIBC_2.27 __pread64_chk F -+GLIBC_2.27 __pread_chk F -+GLIBC_2.27 __printf_chk F -+GLIBC_2.27 __printf_fp F -+GLIBC_2.27 __profile_frequency F -+GLIBC_2.27 __progname D 0x8 -+GLIBC_2.27 __progname_full D 0x8 -+GLIBC_2.27 __ptsname_r_chk F -+GLIBC_2.27 __pwrite64 F -+GLIBC_2.27 __rawmemchr F -+GLIBC_2.27 __rcmd_errstr D 0x8 -+GLIBC_2.27 __read F -+GLIBC_2.27 __read_chk F -+GLIBC_2.27 __readlink_chk F -+GLIBC_2.27 __readlinkat_chk F -+GLIBC_2.27 __realloc_hook D 0x8 -+GLIBC_2.27 __realpath_chk F -+GLIBC_2.27 __recv_chk F -+GLIBC_2.27 __recvfrom_chk F -+GLIBC_2.27 __register_atfork F -+GLIBC_2.27 __res_init F -+GLIBC_2.27 __res_nclose F -+GLIBC_2.27 __res_ninit F -+GLIBC_2.27 __res_randomid F -+GLIBC_2.27 __res_state F -+GLIBC_2.27 __rpc_thread_createerr F -+GLIBC_2.27 __rpc_thread_svc_fdset F -+GLIBC_2.27 __rpc_thread_svc_max_pollfd F -+GLIBC_2.27 __rpc_thread_svc_pollfd F -+GLIBC_2.27 __sbrk F -+GLIBC_2.27 __sched_cpualloc F -+GLIBC_2.27 __sched_cpucount F -+GLIBC_2.27 __sched_cpufree F -+GLIBC_2.27 __sched_get_priority_max F -+GLIBC_2.27 __sched_get_priority_min F -+GLIBC_2.27 __sched_getparam F -+GLIBC_2.27 __sched_getscheduler F -+GLIBC_2.27 __sched_setscheduler F -+GLIBC_2.27 __sched_yield F -+GLIBC_2.27 __select F -+GLIBC_2.27 __send F -+GLIBC_2.27 __setmntent F -+GLIBC_2.27 __setpgid F -+GLIBC_2.27 __sigaction F -+GLIBC_2.27 __signbit F -+GLIBC_2.27 __signbitf F -+GLIBC_2.27 __signbitl F -+GLIBC_2.27 __sigpause F -+GLIBC_2.27 __sigsetjmp F -+GLIBC_2.27 __sigsuspend F -+GLIBC_2.27 __snprintf_chk F -+GLIBC_2.27 __sprintf_chk F -+GLIBC_2.27 __stack_chk_fail F -+GLIBC_2.27 __statfs F -+GLIBC_2.27 __stpcpy F -+GLIBC_2.27 __stpcpy_chk F -+GLIBC_2.27 __stpncpy F -+GLIBC_2.27 __stpncpy_chk F -+GLIBC_2.27 __strcasecmp F -+GLIBC_2.27 __strcasecmp_l F -+GLIBC_2.27 __strcasestr F -+GLIBC_2.27 __strcat_chk F -+GLIBC_2.27 __strcoll_l F -+GLIBC_2.27 __strcpy_chk F -+GLIBC_2.27 __strdup F -+GLIBC_2.27 __strerror_r F -+GLIBC_2.27 __strfmon_l F -+GLIBC_2.27 __strftime_l F -+GLIBC_2.27 __strncasecmp_l F -+GLIBC_2.27 __strncat_chk F -+GLIBC_2.27 __strncpy_chk F -+GLIBC_2.27 __strndup F -+GLIBC_2.27 __strsep_g F -+GLIBC_2.27 __strtod_internal F -+GLIBC_2.27 __strtod_l F -+GLIBC_2.27 __strtof_internal F -+GLIBC_2.27 __strtof_l F -+GLIBC_2.27 __strtok_r F -+GLIBC_2.27 __strtol_internal F -+GLIBC_2.27 __strtol_l F -+GLIBC_2.27 __strtold_internal F -+GLIBC_2.27 __strtold_l F -+GLIBC_2.27 __strtoll_internal F -+GLIBC_2.27 __strtoll_l F -+GLIBC_2.27 __strtoul_internal F -+GLIBC_2.27 __strtoul_l F -+GLIBC_2.27 __strtoull_internal F -+GLIBC_2.27 __strtoull_l F -+GLIBC_2.27 __strverscmp F -+GLIBC_2.27 __strxfrm_l F -+GLIBC_2.27 __swprintf_chk F -+GLIBC_2.27 __sysconf F -+GLIBC_2.27 __syslog_chk F -+GLIBC_2.27 __sysv_signal F -+GLIBC_2.27 __timezone D 0x8 -+GLIBC_2.27 __toascii_l F -+GLIBC_2.27 __tolower_l F -+GLIBC_2.27 __toupper_l F -+GLIBC_2.27 __towctrans F -+GLIBC_2.27 __towctrans_l F -+GLIBC_2.27 __towlower_l F -+GLIBC_2.27 __towupper_l F -+GLIBC_2.27 __ttyname_r_chk F -+GLIBC_2.27 __tzname D 0x10 -+GLIBC_2.27 __uflow F -+GLIBC_2.27 __underflow F -+GLIBC_2.27 __uselocale F -+GLIBC_2.27 __vasprintf_chk F -+GLIBC_2.27 __vdprintf_chk F -+GLIBC_2.27 __vfork F -+GLIBC_2.27 __vfprintf_chk F -+GLIBC_2.27 __vfscanf F -+GLIBC_2.27 __vfwprintf_chk F -+GLIBC_2.27 __vprintf_chk F -+GLIBC_2.27 __vsnprintf F -+GLIBC_2.27 __vsnprintf_chk F -+GLIBC_2.27 __vsprintf_chk F -+GLIBC_2.27 __vsscanf F -+GLIBC_2.27 __vswprintf_chk F -+GLIBC_2.27 __vsyslog_chk F -+GLIBC_2.27 __vwprintf_chk F -+GLIBC_2.27 __wait F -+GLIBC_2.27 __waitpid F -+GLIBC_2.27 __wcpcpy_chk F -+GLIBC_2.27 __wcpncpy_chk F -+GLIBC_2.27 __wcrtomb_chk F -+GLIBC_2.27 __wcscasecmp_l F -+GLIBC_2.27 __wcscat_chk F -+GLIBC_2.27 __wcscoll_l F -+GLIBC_2.27 __wcscpy_chk F -+GLIBC_2.27 __wcsftime_l F -+GLIBC_2.27 __wcsncasecmp_l F -+GLIBC_2.27 __wcsncat_chk F -+GLIBC_2.27 __wcsncpy_chk F -+GLIBC_2.27 __wcsnrtombs_chk F -+GLIBC_2.27 __wcsrtombs_chk F -+GLIBC_2.27 __wcstod_internal F -+GLIBC_2.27 __wcstod_l F -+GLIBC_2.27 __wcstof_internal F -+GLIBC_2.27 __wcstof_l F -+GLIBC_2.27 __wcstol_internal F -+GLIBC_2.27 __wcstol_l F -+GLIBC_2.27 __wcstold_internal F -+GLIBC_2.27 __wcstold_l F -+GLIBC_2.27 __wcstoll_internal F -+GLIBC_2.27 __wcstoll_l F -+GLIBC_2.27 __wcstombs_chk F -+GLIBC_2.27 __wcstoul_internal F -+GLIBC_2.27 __wcstoul_l F -+GLIBC_2.27 __wcstoull_internal F -+GLIBC_2.27 __wcstoull_l F -+GLIBC_2.27 __wcsxfrm_l F -+GLIBC_2.27 __wctomb_chk F -+GLIBC_2.27 __wctrans_l F -+GLIBC_2.27 __wctype_l F -+GLIBC_2.27 __wmemcpy_chk F -+GLIBC_2.27 __wmemmove_chk F -+GLIBC_2.27 __wmempcpy_chk F -+GLIBC_2.27 __wmemset_chk F -+GLIBC_2.27 __woverflow F -+GLIBC_2.27 __wprintf_chk F -+GLIBC_2.27 __write F -+GLIBC_2.27 __wuflow F -+GLIBC_2.27 __wunderflow F -+GLIBC_2.27 __xmknod F -+GLIBC_2.27 __xmknodat F -+GLIBC_2.27 __xpg_basename F -+GLIBC_2.27 __xpg_sigpause F -+GLIBC_2.27 __xpg_strerror_r F -+GLIBC_2.27 __xstat F -+GLIBC_2.27 __xstat64 F -+GLIBC_2.27 _authenticate F -+GLIBC_2.27 _dl_mcount_wrapper F -+GLIBC_2.27 _dl_mcount_wrapper_check F -+GLIBC_2.27 _environ D 0x8 -+GLIBC_2.27 _exit F -+GLIBC_2.27 _flushlbf F -+GLIBC_2.27 _libc_intl_domainname D 0x5 -+GLIBC_2.27 _longjmp F -+GLIBC_2.27 _mcleanup F -+GLIBC_2.27 _mcount F -+GLIBC_2.27 _nl_default_dirname D 0x12 -+GLIBC_2.27 _nl_domain_bindings D 0x8 -+GLIBC_2.27 _nl_msg_cat_cntr D 0x4 -+GLIBC_2.27 _null_auth D 0x18 -+GLIBC_2.27 _obstack_allocated_p F -+GLIBC_2.27 _obstack_begin F -+GLIBC_2.27 _obstack_begin_1 F -+GLIBC_2.27 _obstack_free F -+GLIBC_2.27 _obstack_memory_used F -+GLIBC_2.27 _obstack_newchunk F -+GLIBC_2.27 _res D 0x238 -+GLIBC_2.27 _res_hconf D 0x48 -+GLIBC_2.27 _rpc_dtablesize F -+GLIBC_2.27 _seterr_reply F -+GLIBC_2.27 _setjmp F -+GLIBC_2.27 _sys_errlist D 0x2370 -+GLIBC_2.27 _sys_nerr D 0x4 -+GLIBC_2.27 _sys_siglist D 0x400 -+GLIBC_2.27 _tolower F -+GLIBC_2.27 _toupper F -+GLIBC_2.27 a64l F -+GLIBC_2.27 abort F -+GLIBC_2.27 abs F -+GLIBC_2.27 accept F -+GLIBC_2.27 accept4 F -+GLIBC_2.27 access F -+GLIBC_2.27 acct F -+GLIBC_2.27 addmntent F -+GLIBC_2.27 addseverity F -+GLIBC_2.27 adjtime F -+GLIBC_2.27 adjtimex F -+GLIBC_2.27 alarm F -+GLIBC_2.27 aligned_alloc F -+GLIBC_2.27 alphasort F -+GLIBC_2.27 alphasort64 F -+GLIBC_2.27 argp_err_exit_status D 0x4 -+GLIBC_2.27 argp_error F -+GLIBC_2.27 argp_failure F -+GLIBC_2.27 argp_help F -+GLIBC_2.27 argp_parse F -+GLIBC_2.27 argp_program_bug_address D 0x8 -+GLIBC_2.27 argp_program_version D 0x8 -+GLIBC_2.27 argp_program_version_hook D 0x8 -+GLIBC_2.27 argp_state_help F -+GLIBC_2.27 argp_usage F -+GLIBC_2.27 argz_add F -+GLIBC_2.27 argz_add_sep F -+GLIBC_2.27 argz_append F -+GLIBC_2.27 argz_count F -+GLIBC_2.27 argz_create F -+GLIBC_2.27 argz_create_sep F -+GLIBC_2.27 argz_delete F -+GLIBC_2.27 argz_extract F -+GLIBC_2.27 argz_insert F -+GLIBC_2.27 argz_next F -+GLIBC_2.27 argz_replace F -+GLIBC_2.27 argz_stringify F -+GLIBC_2.27 asctime F -+GLIBC_2.27 asctime_r F -+GLIBC_2.27 asprintf F -+GLIBC_2.27 atof F -+GLIBC_2.27 atoi F -+GLIBC_2.27 atol F -+GLIBC_2.27 atoll F -+GLIBC_2.27 authdes_create F -+GLIBC_2.27 authdes_getucred F -+GLIBC_2.27 authdes_pk_create F -+GLIBC_2.27 authnone_create F -+GLIBC_2.27 authunix_create F -+GLIBC_2.27 authunix_create_default F -+GLIBC_2.27 backtrace F -+GLIBC_2.27 backtrace_symbols F -+GLIBC_2.27 backtrace_symbols_fd F -+GLIBC_2.27 basename F -+GLIBC_2.27 bcmp F -+GLIBC_2.27 bcopy F -+GLIBC_2.27 bind F -+GLIBC_2.27 bind_textdomain_codeset F -+GLIBC_2.27 bindresvport F -+GLIBC_2.27 bindtextdomain F -+GLIBC_2.27 brk F -+GLIBC_2.27 bsd_signal F -+GLIBC_2.27 bsearch F -+GLIBC_2.27 btowc F -+GLIBC_2.27 bzero F -+GLIBC_2.27 c16rtomb F -+GLIBC_2.27 c32rtomb F -+GLIBC_2.27 calloc F -+GLIBC_2.27 callrpc F -+GLIBC_2.27 canonicalize_file_name F -+GLIBC_2.27 capget F -+GLIBC_2.27 capset F -+GLIBC_2.27 catclose F -+GLIBC_2.27 catgets F -+GLIBC_2.27 catopen F -+GLIBC_2.27 cbc_crypt F -+GLIBC_2.27 cfgetispeed F -+GLIBC_2.27 cfgetospeed F -+GLIBC_2.27 cfmakeraw F -+GLIBC_2.27 cfsetispeed F -+GLIBC_2.27 cfsetospeed F -+GLIBC_2.27 cfsetspeed F -+GLIBC_2.27 chdir F -+GLIBC_2.27 chflags F -+GLIBC_2.27 chmod F -+GLIBC_2.27 chown F -+GLIBC_2.27 chroot F -+GLIBC_2.27 clearenv F -+GLIBC_2.27 clearerr F -+GLIBC_2.27 clearerr_unlocked F -+GLIBC_2.27 clnt_broadcast F -+GLIBC_2.27 clnt_create F -+GLIBC_2.27 clnt_pcreateerror F -+GLIBC_2.27 clnt_perrno F -+GLIBC_2.27 clnt_perror F -+GLIBC_2.27 clnt_spcreateerror F -+GLIBC_2.27 clnt_sperrno F -+GLIBC_2.27 clnt_sperror F -+GLIBC_2.27 clntraw_create F -+GLIBC_2.27 clnttcp_create F -+GLIBC_2.27 clntudp_bufcreate F -+GLIBC_2.27 clntudp_create F -+GLIBC_2.27 clntunix_create F -+GLIBC_2.27 clock F -+GLIBC_2.27 clock_adjtime F -+GLIBC_2.27 clock_getcpuclockid F -+GLIBC_2.27 clock_getres F -+GLIBC_2.27 clock_gettime F -+GLIBC_2.27 clock_nanosleep F -+GLIBC_2.27 clock_settime F -+GLIBC_2.27 clone F -+GLIBC_2.27 close F -+GLIBC_2.27 closedir F -+GLIBC_2.27 closelog F -+GLIBC_2.27 confstr F -+GLIBC_2.27 connect F -+GLIBC_2.27 copy_file_range F -+GLIBC_2.27 copysign F -+GLIBC_2.27 copysignf F -+GLIBC_2.27 copysignl F -+GLIBC_2.27 creat F -+GLIBC_2.27 creat64 F -+GLIBC_2.27 ctermid F -+GLIBC_2.27 ctime F -+GLIBC_2.27 ctime_r F -+GLIBC_2.27 cuserid F -+GLIBC_2.27 daemon F -+GLIBC_2.27 daylight D 0x4 -+GLIBC_2.27 dcgettext F -+GLIBC_2.27 dcngettext F -+GLIBC_2.27 delete_module F -+GLIBC_2.27 des_setparity F -+GLIBC_2.27 dgettext F -+GLIBC_2.27 difftime F -+GLIBC_2.27 dirfd F -+GLIBC_2.27 dirname F -+GLIBC_2.27 div F -+GLIBC_2.27 dl_iterate_phdr F -+GLIBC_2.27 dngettext F -+GLIBC_2.27 dprintf F -+GLIBC_2.27 drand48 F -+GLIBC_2.27 drand48_r F -+GLIBC_2.27 dup F -+GLIBC_2.27 dup2 F -+GLIBC_2.27 dup3 F -+GLIBC_2.27 duplocale F -+GLIBC_2.27 dysize F -+GLIBC_2.27 eaccess F -+GLIBC_2.27 ecb_crypt F -+GLIBC_2.27 ecvt F -+GLIBC_2.27 ecvt_r F -+GLIBC_2.27 endaliasent F -+GLIBC_2.27 endfsent F -+GLIBC_2.27 endgrent F -+GLIBC_2.27 endhostent F -+GLIBC_2.27 endmntent F -+GLIBC_2.27 endnetent F -+GLIBC_2.27 endnetgrent F -+GLIBC_2.27 endprotoent F -+GLIBC_2.27 endpwent F -+GLIBC_2.27 endrpcent F -+GLIBC_2.27 endservent F -+GLIBC_2.27 endsgent F -+GLIBC_2.27 endspent F -+GLIBC_2.27 endttyent F -+GLIBC_2.27 endusershell F -+GLIBC_2.27 endutent F -+GLIBC_2.27 endutxent F -+GLIBC_2.27 environ D 0x8 -+GLIBC_2.27 envz_add F -+GLIBC_2.27 envz_entry F -+GLIBC_2.27 envz_get F -+GLIBC_2.27 envz_merge F -+GLIBC_2.27 envz_remove F -+GLIBC_2.27 envz_strip F -+GLIBC_2.27 epoll_create F -+GLIBC_2.27 epoll_create1 F -+GLIBC_2.27 epoll_ctl F -+GLIBC_2.27 epoll_pwait F -+GLIBC_2.27 epoll_wait F -+GLIBC_2.27 erand48 F -+GLIBC_2.27 erand48_r F -+GLIBC_2.27 err F -+GLIBC_2.27 error F -+GLIBC_2.27 error_at_line F -+GLIBC_2.27 error_message_count D 0x4 -+GLIBC_2.27 error_one_per_line D 0x4 -+GLIBC_2.27 error_print_progname D 0x8 -+GLIBC_2.27 errx F -+GLIBC_2.27 ether_aton F -+GLIBC_2.27 ether_aton_r F -+GLIBC_2.27 ether_hostton F -+GLIBC_2.27 ether_line F -+GLIBC_2.27 ether_ntoa F -+GLIBC_2.27 ether_ntoa_r F -+GLIBC_2.27 ether_ntohost F -+GLIBC_2.27 euidaccess F -+GLIBC_2.27 eventfd F -+GLIBC_2.27 eventfd_read F -+GLIBC_2.27 eventfd_write F -+GLIBC_2.27 execl F -+GLIBC_2.27 execle F -+GLIBC_2.27 execlp F -+GLIBC_2.27 execv F -+GLIBC_2.27 execve F -+GLIBC_2.27 execvp F -+GLIBC_2.27 execvpe F -+GLIBC_2.27 exit F -+GLIBC_2.27 explicit_bzero F -+GLIBC_2.27 faccessat F -+GLIBC_2.27 fallocate F -+GLIBC_2.27 fallocate64 F -+GLIBC_2.27 fanotify_init F -+GLIBC_2.27 fanotify_mark F -+GLIBC_2.27 fattach F -+GLIBC_2.27 fchdir F -+GLIBC_2.27 fchflags F -+GLIBC_2.27 fchmod F -+GLIBC_2.27 fchmodat F -+GLIBC_2.27 fchown F -+GLIBC_2.27 fchownat F -+GLIBC_2.27 fclose F -+GLIBC_2.27 fcloseall F -+GLIBC_2.27 fcntl F -+GLIBC_2.27 fcvt F -+GLIBC_2.27 fcvt_r F -+GLIBC_2.27 fdatasync F -+GLIBC_2.27 fdetach F -+GLIBC_2.27 fdopen F -+GLIBC_2.27 fdopendir F -+GLIBC_2.27 feof F -+GLIBC_2.27 feof_unlocked F -+GLIBC_2.27 ferror F -+GLIBC_2.27 ferror_unlocked F -+GLIBC_2.27 fexecve F -+GLIBC_2.27 fflush F -+GLIBC_2.27 fflush_unlocked F -+GLIBC_2.27 ffs F -+GLIBC_2.27 ffsl F -+GLIBC_2.27 ffsll F -+GLIBC_2.27 fgetc F -+GLIBC_2.27 fgetc_unlocked F -+GLIBC_2.27 fgetgrent F -+GLIBC_2.27 fgetgrent_r F -+GLIBC_2.27 fgetpos F -+GLIBC_2.27 fgetpos64 F -+GLIBC_2.27 fgetpwent F -+GLIBC_2.27 fgetpwent_r F -+GLIBC_2.27 fgets F -+GLIBC_2.27 fgets_unlocked F -+GLIBC_2.27 fgetsgent F -+GLIBC_2.27 fgetsgent_r F -+GLIBC_2.27 fgetspent F -+GLIBC_2.27 fgetspent_r F -+GLIBC_2.27 fgetwc F -+GLIBC_2.27 fgetwc_unlocked F -+GLIBC_2.27 fgetws F -+GLIBC_2.27 fgetws_unlocked F -+GLIBC_2.27 fgetxattr F -+GLIBC_2.27 fileno F -+GLIBC_2.27 fileno_unlocked F -+GLIBC_2.27 finite F -+GLIBC_2.27 finitef F -+GLIBC_2.27 finitel F -+GLIBC_2.27 flistxattr F -+GLIBC_2.27 flock F -+GLIBC_2.27 flockfile F -+GLIBC_2.27 fmemopen F -+GLIBC_2.27 fmtmsg F -+GLIBC_2.27 fnmatch F -+GLIBC_2.27 fopen F -+GLIBC_2.27 fopen64 F -+GLIBC_2.27 fopencookie F -+GLIBC_2.27 fork F -+GLIBC_2.27 fpathconf F -+GLIBC_2.27 fprintf F -+GLIBC_2.27 fputc F -+GLIBC_2.27 fputc_unlocked F -+GLIBC_2.27 fputs F -+GLIBC_2.27 fputs_unlocked F -+GLIBC_2.27 fputwc F -+GLIBC_2.27 fputwc_unlocked F -+GLIBC_2.27 fputws F -+GLIBC_2.27 fputws_unlocked F -+GLIBC_2.27 fread F -+GLIBC_2.27 fread_unlocked F -+GLIBC_2.27 free F -+GLIBC_2.27 freeaddrinfo F -+GLIBC_2.27 freeifaddrs F -+GLIBC_2.27 freelocale F -+GLIBC_2.27 fremovexattr F -+GLIBC_2.27 freopen F -+GLIBC_2.27 freopen64 F -+GLIBC_2.27 frexp F -+GLIBC_2.27 frexpf F -+GLIBC_2.27 frexpl F -+GLIBC_2.27 fscanf F -+GLIBC_2.27 fseek F -+GLIBC_2.27 fseeko F -+GLIBC_2.27 fseeko64 F -+GLIBC_2.27 fsetpos F -+GLIBC_2.27 fsetpos64 F -+GLIBC_2.27 fsetxattr F -+GLIBC_2.27 fstatfs F -+GLIBC_2.27 fstatfs64 F -+GLIBC_2.27 fstatvfs F -+GLIBC_2.27 fstatvfs64 F -+GLIBC_2.27 fsync F -+GLIBC_2.27 ftell F -+GLIBC_2.27 ftello F -+GLIBC_2.27 ftello64 F -+GLIBC_2.27 ftime F -+GLIBC_2.27 ftok F -+GLIBC_2.27 ftruncate F -+GLIBC_2.27 ftruncate64 F -+GLIBC_2.27 ftrylockfile F -+GLIBC_2.27 fts64_children F -+GLIBC_2.27 fts64_close F -+GLIBC_2.27 fts64_open F -+GLIBC_2.27 fts64_read F -+GLIBC_2.27 fts64_set F -+GLIBC_2.27 fts_children F -+GLIBC_2.27 fts_close F -+GLIBC_2.27 fts_open F -+GLIBC_2.27 fts_read F -+GLIBC_2.27 fts_set F -+GLIBC_2.27 ftw F -+GLIBC_2.27 ftw64 F -+GLIBC_2.27 funlockfile F -+GLIBC_2.27 futimens F -+GLIBC_2.27 futimes F -+GLIBC_2.27 futimesat F -+GLIBC_2.27 fwide F -+GLIBC_2.27 fwprintf F -+GLIBC_2.27 fwrite F -+GLIBC_2.27 fwrite_unlocked F -+GLIBC_2.27 fwscanf F -+GLIBC_2.27 gai_strerror F -+GLIBC_2.27 gcvt F -+GLIBC_2.27 get_avphys_pages F -+GLIBC_2.27 get_current_dir_name F -+GLIBC_2.27 get_myaddress F -+GLIBC_2.27 get_nprocs F -+GLIBC_2.27 get_nprocs_conf F -+GLIBC_2.27 get_phys_pages F -+GLIBC_2.27 getaddrinfo F -+GLIBC_2.27 getaliasbyname F -+GLIBC_2.27 getaliasbyname_r F -+GLIBC_2.27 getaliasent F -+GLIBC_2.27 getaliasent_r F -+GLIBC_2.27 getauxval F -+GLIBC_2.27 getc F -+GLIBC_2.27 getc_unlocked F -+GLIBC_2.27 getchar F -+GLIBC_2.27 getchar_unlocked F -+GLIBC_2.27 getcontext F -+GLIBC_2.27 getcwd F -+GLIBC_2.27 getdate F -+GLIBC_2.27 getdate_err D 0x4 -+GLIBC_2.27 getdate_r F -+GLIBC_2.27 getdelim F -+GLIBC_2.27 getdirentries F -+GLIBC_2.27 getdirentries64 F -+GLIBC_2.27 getdomainname F -+GLIBC_2.27 getdtablesize F -+GLIBC_2.27 getegid F -+GLIBC_2.27 getentropy F -+GLIBC_2.27 getenv F -+GLIBC_2.27 geteuid F -+GLIBC_2.27 getfsent F -+GLIBC_2.27 getfsfile F -+GLIBC_2.27 getfsspec F -+GLIBC_2.27 getgid F -+GLIBC_2.27 getgrent F -+GLIBC_2.27 getgrent_r F -+GLIBC_2.27 getgrgid F -+GLIBC_2.27 getgrgid_r F -+GLIBC_2.27 getgrnam F -+GLIBC_2.27 getgrnam_r F -+GLIBC_2.27 getgrouplist F -+GLIBC_2.27 getgroups F -+GLIBC_2.27 gethostbyaddr F -+GLIBC_2.27 gethostbyaddr_r F -+GLIBC_2.27 gethostbyname F -+GLIBC_2.27 gethostbyname2 F -+GLIBC_2.27 gethostbyname2_r F -+GLIBC_2.27 gethostbyname_r F -+GLIBC_2.27 gethostent F -+GLIBC_2.27 gethostent_r F -+GLIBC_2.27 gethostid F -+GLIBC_2.27 gethostname F -+GLIBC_2.27 getifaddrs F -+GLIBC_2.27 getipv4sourcefilter F -+GLIBC_2.27 getitimer F -+GLIBC_2.27 getline F -+GLIBC_2.27 getloadavg F -+GLIBC_2.27 getlogin F -+GLIBC_2.27 getlogin_r F -+GLIBC_2.27 getmntent F -+GLIBC_2.27 getmntent_r F -+GLIBC_2.27 getmsg F -+GLIBC_2.27 getnameinfo F -+GLIBC_2.27 getnetbyaddr F -+GLIBC_2.27 getnetbyaddr_r F -+GLIBC_2.27 getnetbyname F -+GLIBC_2.27 getnetbyname_r F -+GLIBC_2.27 getnetent F -+GLIBC_2.27 getnetent_r F -+GLIBC_2.27 getnetgrent F -+GLIBC_2.27 getnetgrent_r F -+GLIBC_2.27 getnetname F -+GLIBC_2.27 getopt F -+GLIBC_2.27 getopt_long F -+GLIBC_2.27 getopt_long_only F -+GLIBC_2.27 getpagesize F -+GLIBC_2.27 getpass F -+GLIBC_2.27 getpeername F -+GLIBC_2.27 getpgid F -+GLIBC_2.27 getpgrp F -+GLIBC_2.27 getpid F -+GLIBC_2.27 getpmsg F -+GLIBC_2.27 getppid F -+GLIBC_2.27 getpriority F -+GLIBC_2.27 getprotobyname F -+GLIBC_2.27 getprotobyname_r F -+GLIBC_2.27 getprotobynumber F -+GLIBC_2.27 getprotobynumber_r F -+GLIBC_2.27 getprotoent F -+GLIBC_2.27 getprotoent_r F -+GLIBC_2.27 getpt F -+GLIBC_2.27 getpublickey F -+GLIBC_2.27 getpw F -+GLIBC_2.27 getpwent F -+GLIBC_2.27 getpwent_r F -+GLIBC_2.27 getpwnam F -+GLIBC_2.27 getpwnam_r F -+GLIBC_2.27 getpwuid F -+GLIBC_2.27 getpwuid_r F -+GLIBC_2.27 getrandom F -+GLIBC_2.27 getresgid F -+GLIBC_2.27 getresuid F -+GLIBC_2.27 getrlimit F -+GLIBC_2.27 getrlimit64 F -+GLIBC_2.27 getrpcbyname F -+GLIBC_2.27 getrpcbyname_r F -+GLIBC_2.27 getrpcbynumber F -+GLIBC_2.27 getrpcbynumber_r F -+GLIBC_2.27 getrpcent F -+GLIBC_2.27 getrpcent_r F -+GLIBC_2.27 getrpcport F -+GLIBC_2.27 getrusage F -+GLIBC_2.27 gets F -+GLIBC_2.27 getsecretkey F -+GLIBC_2.27 getservbyname F -+GLIBC_2.27 getservbyname_r F -+GLIBC_2.27 getservbyport F -+GLIBC_2.27 getservbyport_r F -+GLIBC_2.27 getservent F -+GLIBC_2.27 getservent_r F -+GLIBC_2.27 getsgent F -+GLIBC_2.27 getsgent_r F -+GLIBC_2.27 getsgnam F -+GLIBC_2.27 getsgnam_r F -+GLIBC_2.27 getsid F -+GLIBC_2.27 getsockname F -+GLIBC_2.27 getsockopt F -+GLIBC_2.27 getsourcefilter F -+GLIBC_2.27 getspent F -+GLIBC_2.27 getspent_r F -+GLIBC_2.27 getspnam F -+GLIBC_2.27 getspnam_r F -+GLIBC_2.27 getsubopt F -+GLIBC_2.27 gettext F -+GLIBC_2.27 gettimeofday F -+GLIBC_2.27 getttyent F -+GLIBC_2.27 getttynam F -+GLIBC_2.27 getuid F -+GLIBC_2.27 getusershell F -+GLIBC_2.27 getutent F -+GLIBC_2.27 getutent_r F -+GLIBC_2.27 getutid F -+GLIBC_2.27 getutid_r F -+GLIBC_2.27 getutline F -+GLIBC_2.27 getutline_r F -+GLIBC_2.27 getutmp F -+GLIBC_2.27 getutmpx F -+GLIBC_2.27 getutxent F -+GLIBC_2.27 getutxid F -+GLIBC_2.27 getutxline F -+GLIBC_2.27 getw F -+GLIBC_2.27 getwc F -+GLIBC_2.27 getwc_unlocked F -+GLIBC_2.27 getwchar F -+GLIBC_2.27 getwchar_unlocked F -+GLIBC_2.27 getwd F -+GLIBC_2.27 getxattr F -+GLIBC_2.27 glob F -+GLIBC_2.27 glob64 F -+GLIBC_2.27 glob_pattern_p F -+GLIBC_2.27 globfree F -+GLIBC_2.27 globfree64 F -+GLIBC_2.27 gmtime F -+GLIBC_2.27 gmtime_r F -+GLIBC_2.27 gnu_dev_major F -+GLIBC_2.27 gnu_dev_makedev F -+GLIBC_2.27 gnu_dev_minor F -+GLIBC_2.27 gnu_get_libc_release F -+GLIBC_2.27 gnu_get_libc_version F -+GLIBC_2.27 grantpt F -+GLIBC_2.27 group_member F -+GLIBC_2.27 gsignal F -+GLIBC_2.27 gtty F -+GLIBC_2.27 h_errlist D 0x28 -+GLIBC_2.27 h_nerr D 0x4 -+GLIBC_2.27 hasmntopt F -+GLIBC_2.27 hcreate F -+GLIBC_2.27 hcreate_r F -+GLIBC_2.27 hdestroy F -+GLIBC_2.27 hdestroy_r F -+GLIBC_2.27 herror F -+GLIBC_2.27 host2netname F -+GLIBC_2.27 hsearch F -+GLIBC_2.27 hsearch_r F -+GLIBC_2.27 hstrerror F -+GLIBC_2.27 htonl F -+GLIBC_2.27 htons F -+GLIBC_2.27 iconv F -+GLIBC_2.27 iconv_close F -+GLIBC_2.27 iconv_open F -+GLIBC_2.27 if_freenameindex F -+GLIBC_2.27 if_indextoname F -+GLIBC_2.27 if_nameindex F -+GLIBC_2.27 if_nametoindex F -+GLIBC_2.27 imaxabs F -+GLIBC_2.27 imaxdiv F -+GLIBC_2.27 in6addr_any D 0x10 -+GLIBC_2.27 in6addr_loopback D 0x10 -+GLIBC_2.27 index F -+GLIBC_2.27 inet6_opt_append F -+GLIBC_2.27 inet6_opt_find F -+GLIBC_2.27 inet6_opt_finish F -+GLIBC_2.27 inet6_opt_get_val F -+GLIBC_2.27 inet6_opt_init F -+GLIBC_2.27 inet6_opt_next F -+GLIBC_2.27 inet6_opt_set_val F -+GLIBC_2.27 inet6_option_alloc F -+GLIBC_2.27 inet6_option_append F -+GLIBC_2.27 inet6_option_find F -+GLIBC_2.27 inet6_option_init F -+GLIBC_2.27 inet6_option_next F -+GLIBC_2.27 inet6_option_space F -+GLIBC_2.27 inet6_rth_add F -+GLIBC_2.27 inet6_rth_getaddr F -+GLIBC_2.27 inet6_rth_init F -+GLIBC_2.27 inet6_rth_reverse F -+GLIBC_2.27 inet6_rth_segments F -+GLIBC_2.27 inet6_rth_space F -+GLIBC_2.27 inet_addr F -+GLIBC_2.27 inet_aton F -+GLIBC_2.27 inet_lnaof F -+GLIBC_2.27 inet_makeaddr F -+GLIBC_2.27 inet_netof F -+GLIBC_2.27 inet_network F -+GLIBC_2.27 inet_nsap_addr F -+GLIBC_2.27 inet_nsap_ntoa F -+GLIBC_2.27 inet_ntoa F -+GLIBC_2.27 inet_ntop F -+GLIBC_2.27 inet_pton F -+GLIBC_2.27 init_module F -+GLIBC_2.27 initgroups F -+GLIBC_2.27 initstate F -+GLIBC_2.27 initstate_r F -+GLIBC_2.27 innetgr F -+GLIBC_2.27 inotify_add_watch F -+GLIBC_2.27 inotify_init F -+GLIBC_2.27 inotify_init1 F -+GLIBC_2.27 inotify_rm_watch F -+GLIBC_2.27 insque F -+GLIBC_2.27 ioctl F -+GLIBC_2.27 iruserok F -+GLIBC_2.27 iruserok_af F -+GLIBC_2.27 isalnum F -+GLIBC_2.27 isalnum_l F -+GLIBC_2.27 isalpha F -+GLIBC_2.27 isalpha_l F -+GLIBC_2.27 isascii F -+GLIBC_2.27 isastream F -+GLIBC_2.27 isatty F -+GLIBC_2.27 isblank F -+GLIBC_2.27 isblank_l F -+GLIBC_2.27 iscntrl F -+GLIBC_2.27 iscntrl_l F -+GLIBC_2.27 isctype F -+GLIBC_2.27 isdigit F -+GLIBC_2.27 isdigit_l F -+GLIBC_2.27 isfdtype F -+GLIBC_2.27 isgraph F -+GLIBC_2.27 isgraph_l F -+GLIBC_2.27 isinf F -+GLIBC_2.27 isinff F -+GLIBC_2.27 isinfl F -+GLIBC_2.27 islower F -+GLIBC_2.27 islower_l F -+GLIBC_2.27 isnan F -+GLIBC_2.27 isnanf F -+GLIBC_2.27 isnanl F -+GLIBC_2.27 isprint F -+GLIBC_2.27 isprint_l F -+GLIBC_2.27 ispunct F -+GLIBC_2.27 ispunct_l F -+GLIBC_2.27 isspace F -+GLIBC_2.27 isspace_l F -+GLIBC_2.27 isupper F -+GLIBC_2.27 isupper_l F -+GLIBC_2.27 iswalnum F -+GLIBC_2.27 iswalnum_l F -+GLIBC_2.27 iswalpha F -+GLIBC_2.27 iswalpha_l F -+GLIBC_2.27 iswblank F -+GLIBC_2.27 iswblank_l F -+GLIBC_2.27 iswcntrl F -+GLIBC_2.27 iswcntrl_l F -+GLIBC_2.27 iswctype F -+GLIBC_2.27 iswctype_l F -+GLIBC_2.27 iswdigit F -+GLIBC_2.27 iswdigit_l F -+GLIBC_2.27 iswgraph F -+GLIBC_2.27 iswgraph_l F -+GLIBC_2.27 iswlower F -+GLIBC_2.27 iswlower_l F -+GLIBC_2.27 iswprint F -+GLIBC_2.27 iswprint_l F -+GLIBC_2.27 iswpunct F -+GLIBC_2.27 iswpunct_l F -+GLIBC_2.27 iswspace F -+GLIBC_2.27 iswspace_l F -+GLIBC_2.27 iswupper F -+GLIBC_2.27 iswupper_l F -+GLIBC_2.27 iswxdigit F -+GLIBC_2.27 iswxdigit_l F -+GLIBC_2.27 isxdigit F -+GLIBC_2.27 isxdigit_l F -+GLIBC_2.27 jrand48 F -+GLIBC_2.27 jrand48_r F -+GLIBC_2.27 key_decryptsession F -+GLIBC_2.27 key_decryptsession_pk F -+GLIBC_2.27 key_encryptsession F -+GLIBC_2.27 key_encryptsession_pk F -+GLIBC_2.27 key_gendes F -+GLIBC_2.27 key_get_conv F -+GLIBC_2.27 key_secretkey_is_set F -+GLIBC_2.27 key_setnet F -+GLIBC_2.27 key_setsecret F -+GLIBC_2.27 kill F -+GLIBC_2.27 killpg F -+GLIBC_2.27 klogctl F -+GLIBC_2.27 l64a F -+GLIBC_2.27 labs F -+GLIBC_2.27 lchmod F -+GLIBC_2.27 lchown F -+GLIBC_2.27 lckpwdf F -+GLIBC_2.27 lcong48 F -+GLIBC_2.27 lcong48_r F -+GLIBC_2.27 ldexp F -+GLIBC_2.27 ldexpf F -+GLIBC_2.27 ldexpl F -+GLIBC_2.27 ldiv F -+GLIBC_2.27 lfind F -+GLIBC_2.27 lgetxattr F -+GLIBC_2.27 link F -+GLIBC_2.27 linkat F -+GLIBC_2.27 listen F -+GLIBC_2.27 listxattr F -+GLIBC_2.27 llabs F -+GLIBC_2.27 lldiv F -+GLIBC_2.27 llistxattr F -+GLIBC_2.27 llseek F -+GLIBC_2.27 localeconv F -+GLIBC_2.27 localtime F -+GLIBC_2.27 localtime_r F -+GLIBC_2.27 lockf F -+GLIBC_2.27 lockf64 F -+GLIBC_2.27 longjmp F -+GLIBC_2.27 lrand48 F -+GLIBC_2.27 lrand48_r F -+GLIBC_2.27 lremovexattr F -+GLIBC_2.27 lsearch F -+GLIBC_2.27 lseek F -+GLIBC_2.27 lseek64 F -+GLIBC_2.27 lsetxattr F -+GLIBC_2.27 lutimes F -+GLIBC_2.27 madvise F -+GLIBC_2.27 makecontext F -+GLIBC_2.27 mallinfo F -+GLIBC_2.27 malloc F -+GLIBC_2.27 malloc_info F -+GLIBC_2.27 malloc_stats F -+GLIBC_2.27 malloc_trim F -+GLIBC_2.27 malloc_usable_size F -+GLIBC_2.27 mallopt F -+GLIBC_2.27 mallwatch D 0x8 -+GLIBC_2.27 mblen F -+GLIBC_2.27 mbrlen F -+GLIBC_2.27 mbrtoc16 F -+GLIBC_2.27 mbrtoc32 F -+GLIBC_2.27 mbrtowc F -+GLIBC_2.27 mbsinit F -+GLIBC_2.27 mbsnrtowcs F -+GLIBC_2.27 mbsrtowcs F -+GLIBC_2.27 mbstowcs F -+GLIBC_2.27 mbtowc F -+GLIBC_2.27 mcheck F -+GLIBC_2.27 mcheck_check_all F -+GLIBC_2.27 mcheck_pedantic F -+GLIBC_2.27 memalign F -+GLIBC_2.27 memccpy F -+GLIBC_2.27 memchr F -+GLIBC_2.27 memcmp F -+GLIBC_2.27 memcpy F -+GLIBC_2.27 memfd_create F -+GLIBC_2.27 memfrob F -+GLIBC_2.27 memmem F -+GLIBC_2.27 memmove F -+GLIBC_2.27 mempcpy F -+GLIBC_2.27 memrchr F -+GLIBC_2.27 memset F -+GLIBC_2.27 mincore F -+GLIBC_2.27 mkdir F -+GLIBC_2.27 mkdirat F -+GLIBC_2.27 mkdtemp F -+GLIBC_2.27 mkfifo F -+GLIBC_2.27 mkfifoat F -+GLIBC_2.27 mkostemp F -+GLIBC_2.27 mkostemp64 F -+GLIBC_2.27 mkostemps F -+GLIBC_2.27 mkostemps64 F -+GLIBC_2.27 mkstemp F -+GLIBC_2.27 mkstemp64 F -+GLIBC_2.27 mkstemps F -+GLIBC_2.27 mkstemps64 F -+GLIBC_2.27 mktemp F -+GLIBC_2.27 mktime F -+GLIBC_2.27 mlock F -+GLIBC_2.27 mlock2 F -+GLIBC_2.27 mlockall F -+GLIBC_2.27 mmap F -+GLIBC_2.27 mmap64 F -+GLIBC_2.27 modf F -+GLIBC_2.27 modff F -+GLIBC_2.27 modfl F -+GLIBC_2.27 moncontrol F -+GLIBC_2.27 monstartup F -+GLIBC_2.27 mount F -+GLIBC_2.27 mprobe F -+GLIBC_2.27 mprotect F -+GLIBC_2.27 mrand48 F -+GLIBC_2.27 mrand48_r F -+GLIBC_2.27 mremap F -+GLIBC_2.27 msgctl F -+GLIBC_2.27 msgget F -+GLIBC_2.27 msgrcv F -+GLIBC_2.27 msgsnd F -+GLIBC_2.27 msync F -+GLIBC_2.27 mtrace F -+GLIBC_2.27 munlock F -+GLIBC_2.27 munlockall F -+GLIBC_2.27 munmap F -+GLIBC_2.27 muntrace F -+GLIBC_2.27 name_to_handle_at F -+GLIBC_2.27 nanosleep F -+GLIBC_2.27 netname2host F -+GLIBC_2.27 netname2user F -+GLIBC_2.27 newlocale F -+GLIBC_2.27 nfsservctl F -+GLIBC_2.27 nftw F -+GLIBC_2.27 nftw64 F -+GLIBC_2.27 ngettext F -+GLIBC_2.27 nice F -+GLIBC_2.27 nl_langinfo F -+GLIBC_2.27 nl_langinfo_l F -+GLIBC_2.27 nrand48 F -+GLIBC_2.27 nrand48_r F -+GLIBC_2.27 ntohl F -+GLIBC_2.27 ntohs F -+GLIBC_2.27 ntp_adjtime F -+GLIBC_2.27 ntp_gettime F -+GLIBC_2.27 ntp_gettimex F -+GLIBC_2.27 obstack_alloc_failed_handler D 0x8 -+GLIBC_2.27 obstack_exit_failure D 0x4 -+GLIBC_2.27 obstack_free F -+GLIBC_2.27 obstack_printf F -+GLIBC_2.27 obstack_vprintf F -+GLIBC_2.27 on_exit F -+GLIBC_2.27 open F -+GLIBC_2.27 open64 F -+GLIBC_2.27 open_by_handle_at F -+GLIBC_2.27 open_memstream F -+GLIBC_2.27 open_wmemstream F -+GLIBC_2.27 openat F -+GLIBC_2.27 openat64 F -+GLIBC_2.27 opendir F -+GLIBC_2.27 openlog F -+GLIBC_2.27 optarg D 0x8 -+GLIBC_2.27 opterr D 0x4 -+GLIBC_2.27 optind D 0x4 -+GLIBC_2.27 optopt D 0x4 -+GLIBC_2.27 parse_printf_format F -+GLIBC_2.27 passwd2des F -+GLIBC_2.27 pathconf F -+GLIBC_2.27 pause F -+GLIBC_2.27 pclose F -+GLIBC_2.27 perror F -+GLIBC_2.27 personality F -+GLIBC_2.27 pipe F -+GLIBC_2.27 pipe2 F -+GLIBC_2.27 pivot_root F -+GLIBC_2.27 pkey_alloc F -+GLIBC_2.27 pkey_free F -+GLIBC_2.27 pkey_get F -+GLIBC_2.27 pkey_mprotect F -+GLIBC_2.27 pkey_set F -+GLIBC_2.27 pmap_getmaps F -+GLIBC_2.27 pmap_getport F -+GLIBC_2.27 pmap_rmtcall F -+GLIBC_2.27 pmap_set F -+GLIBC_2.27 pmap_unset F -+GLIBC_2.27 poll F -+GLIBC_2.27 popen F -+GLIBC_2.27 posix_fadvise F -+GLIBC_2.27 posix_fadvise64 F -+GLIBC_2.27 posix_fallocate F -+GLIBC_2.27 posix_fallocate64 F -+GLIBC_2.27 posix_madvise F -+GLIBC_2.27 posix_memalign F -+GLIBC_2.27 posix_openpt F -+GLIBC_2.27 posix_spawn F -+GLIBC_2.27 posix_spawn_file_actions_addclose F -+GLIBC_2.27 posix_spawn_file_actions_adddup2 F -+GLIBC_2.27 posix_spawn_file_actions_addopen F -+GLIBC_2.27 posix_spawn_file_actions_destroy F -+GLIBC_2.27 posix_spawn_file_actions_init F -+GLIBC_2.27 posix_spawnattr_destroy F -+GLIBC_2.27 posix_spawnattr_getflags F -+GLIBC_2.27 posix_spawnattr_getpgroup F -+GLIBC_2.27 posix_spawnattr_getschedparam F -+GLIBC_2.27 posix_spawnattr_getschedpolicy F -+GLIBC_2.27 posix_spawnattr_getsigdefault F -+GLIBC_2.27 posix_spawnattr_getsigmask F -+GLIBC_2.27 posix_spawnattr_init F -+GLIBC_2.27 posix_spawnattr_setflags F -+GLIBC_2.27 posix_spawnattr_setpgroup F -+GLIBC_2.27 posix_spawnattr_setschedparam F -+GLIBC_2.27 posix_spawnattr_setschedpolicy F -+GLIBC_2.27 posix_spawnattr_setsigdefault F -+GLIBC_2.27 posix_spawnattr_setsigmask F -+GLIBC_2.27 posix_spawnp F -+GLIBC_2.27 ppoll F -+GLIBC_2.27 prctl F -+GLIBC_2.27 pread F -+GLIBC_2.27 pread64 F -+GLIBC_2.27 preadv F -+GLIBC_2.27 preadv2 F -+GLIBC_2.27 preadv64 F -+GLIBC_2.27 preadv64v2 F -+GLIBC_2.27 printf F -+GLIBC_2.27 printf_size F -+GLIBC_2.27 printf_size_info F -+GLIBC_2.27 prlimit F -+GLIBC_2.27 prlimit64 F -+GLIBC_2.27 process_vm_readv F -+GLIBC_2.27 process_vm_writev F -+GLIBC_2.27 profil F -+GLIBC_2.27 program_invocation_name D 0x8 -+GLIBC_2.27 program_invocation_short_name D 0x8 -+GLIBC_2.27 pselect F -+GLIBC_2.27 psiginfo F -+GLIBC_2.27 psignal F -+GLIBC_2.27 pthread_attr_destroy F -+GLIBC_2.27 pthread_attr_getdetachstate F -+GLIBC_2.27 pthread_attr_getinheritsched F -+GLIBC_2.27 pthread_attr_getschedparam F -+GLIBC_2.27 pthread_attr_getschedpolicy F -+GLIBC_2.27 pthread_attr_getscope F -+GLIBC_2.27 pthread_attr_init F -+GLIBC_2.27 pthread_attr_setdetachstate F -+GLIBC_2.27 pthread_attr_setinheritsched F -+GLIBC_2.27 pthread_attr_setschedparam F -+GLIBC_2.27 pthread_attr_setschedpolicy F -+GLIBC_2.27 pthread_attr_setscope F -+GLIBC_2.27 pthread_cond_broadcast F -+GLIBC_2.27 pthread_cond_destroy F -+GLIBC_2.27 pthread_cond_init F -+GLIBC_2.27 pthread_cond_signal F -+GLIBC_2.27 pthread_cond_timedwait F -+GLIBC_2.27 pthread_cond_wait F -+GLIBC_2.27 pthread_condattr_destroy F -+GLIBC_2.27 pthread_condattr_init F -+GLIBC_2.27 pthread_equal F -+GLIBC_2.27 pthread_exit F -+GLIBC_2.27 pthread_getschedparam F -+GLIBC_2.27 pthread_mutex_destroy F -+GLIBC_2.27 pthread_mutex_init F -+GLIBC_2.27 pthread_mutex_lock F -+GLIBC_2.27 pthread_mutex_unlock F -+GLIBC_2.27 pthread_self F -+GLIBC_2.27 pthread_setcancelstate F -+GLIBC_2.27 pthread_setcanceltype F -+GLIBC_2.27 pthread_setschedparam F -+GLIBC_2.27 ptrace F -+GLIBC_2.27 ptsname F -+GLIBC_2.27 ptsname_r F -+GLIBC_2.27 putc F -+GLIBC_2.27 putc_unlocked F -+GLIBC_2.27 putchar F -+GLIBC_2.27 putchar_unlocked F -+GLIBC_2.27 putenv F -+GLIBC_2.27 putgrent F -+GLIBC_2.27 putmsg F -+GLIBC_2.27 putpmsg F -+GLIBC_2.27 putpwent F -+GLIBC_2.27 puts F -+GLIBC_2.27 putsgent F -+GLIBC_2.27 putspent F -+GLIBC_2.27 pututline F -+GLIBC_2.27 pututxline F -+GLIBC_2.27 putw F -+GLIBC_2.27 putwc F -+GLIBC_2.27 putwc_unlocked F -+GLIBC_2.27 putwchar F -+GLIBC_2.27 putwchar_unlocked F -+GLIBC_2.27 pvalloc F -+GLIBC_2.27 pwrite F -+GLIBC_2.27 pwrite64 F -+GLIBC_2.27 pwritev F -+GLIBC_2.27 pwritev2 F -+GLIBC_2.27 pwritev64 F -+GLIBC_2.27 pwritev64v2 F -+GLIBC_2.27 qecvt F -+GLIBC_2.27 qecvt_r F -+GLIBC_2.27 qfcvt F -+GLIBC_2.27 qfcvt_r F -+GLIBC_2.27 qgcvt F -+GLIBC_2.27 qsort F -+GLIBC_2.27 qsort_r F -+GLIBC_2.27 quick_exit F -+GLIBC_2.27 quotactl F -+GLIBC_2.27 raise F -+GLIBC_2.27 rand F -+GLIBC_2.27 rand_r F -+GLIBC_2.27 random F -+GLIBC_2.27 random_r F -+GLIBC_2.27 rawmemchr F -+GLIBC_2.27 rcmd F -+GLIBC_2.27 rcmd_af F -+GLIBC_2.27 re_comp F -+GLIBC_2.27 re_compile_fastmap F -+GLIBC_2.27 re_compile_pattern F -+GLIBC_2.27 re_exec F -+GLIBC_2.27 re_match F -+GLIBC_2.27 re_match_2 F -+GLIBC_2.27 re_search F -+GLIBC_2.27 re_search_2 F -+GLIBC_2.27 re_set_registers F -+GLIBC_2.27 re_set_syntax F -+GLIBC_2.27 re_syntax_options D 0x8 -+GLIBC_2.27 read F -+GLIBC_2.27 readahead F -+GLIBC_2.27 readdir F -+GLIBC_2.27 readdir64 F -+GLIBC_2.27 readdir64_r F -+GLIBC_2.27 readdir_r F -+GLIBC_2.27 readlink F -+GLIBC_2.27 readlinkat F -+GLIBC_2.27 readv F -+GLIBC_2.27 realloc F -+GLIBC_2.27 reallocarray F -+GLIBC_2.27 realpath F -+GLIBC_2.27 reboot F -+GLIBC_2.27 recv F -+GLIBC_2.27 recvfrom F -+GLIBC_2.27 recvmmsg F -+GLIBC_2.27 recvmsg F -+GLIBC_2.27 regcomp F -+GLIBC_2.27 regerror F -+GLIBC_2.27 regexec F -+GLIBC_2.27 regfree F -+GLIBC_2.27 register_printf_function F -+GLIBC_2.27 register_printf_modifier F -+GLIBC_2.27 register_printf_specifier F -+GLIBC_2.27 register_printf_type F -+GLIBC_2.27 registerrpc F -+GLIBC_2.27 remap_file_pages F -+GLIBC_2.27 remove F -+GLIBC_2.27 removexattr F -+GLIBC_2.27 remque F -+GLIBC_2.27 rename F -+GLIBC_2.27 renameat F -+GLIBC_2.27 revoke F -+GLIBC_2.27 rewind F -+GLIBC_2.27 rewinddir F -+GLIBC_2.27 rexec F -+GLIBC_2.27 rexec_af F -+GLIBC_2.27 rexecoptions D 0x4 -+GLIBC_2.27 rindex F -+GLIBC_2.27 rmdir F -+GLIBC_2.27 rpc_createerr D 0x20 -+GLIBC_2.27 rpmatch F -+GLIBC_2.27 rresvport F -+GLIBC_2.27 rresvport_af F -+GLIBC_2.27 rtime F -+GLIBC_2.27 ruserok F -+GLIBC_2.27 ruserok_af F -+GLIBC_2.27 ruserpass F -+GLIBC_2.27 sbrk F -+GLIBC_2.27 scalbn F -+GLIBC_2.27 scalbnf F -+GLIBC_2.27 scalbnl F -+GLIBC_2.27 scandir F -+GLIBC_2.27 scandir64 F -+GLIBC_2.27 scandirat F -+GLIBC_2.27 scandirat64 F -+GLIBC_2.27 scanf F -+GLIBC_2.27 sched_get_priority_max F -+GLIBC_2.27 sched_get_priority_min F -+GLIBC_2.27 sched_getaffinity F -+GLIBC_2.27 sched_getcpu F -+GLIBC_2.27 sched_getparam F -+GLIBC_2.27 sched_getscheduler F -+GLIBC_2.27 sched_rr_get_interval F -+GLIBC_2.27 sched_setaffinity F -+GLIBC_2.27 sched_setparam F -+GLIBC_2.27 sched_setscheduler F -+GLIBC_2.27 sched_yield F -+GLIBC_2.27 secure_getenv F -+GLIBC_2.27 seed48 F -+GLIBC_2.27 seed48_r F -+GLIBC_2.27 seekdir F -+GLIBC_2.27 select F -+GLIBC_2.27 semctl F -+GLIBC_2.27 semget F -+GLIBC_2.27 semop F -+GLIBC_2.27 semtimedop F -+GLIBC_2.27 send F -+GLIBC_2.27 sendfile F -+GLIBC_2.27 sendfile64 F -+GLIBC_2.27 sendmmsg F -+GLIBC_2.27 sendmsg F -+GLIBC_2.27 sendto F -+GLIBC_2.27 setaliasent F -+GLIBC_2.27 setbuf F -+GLIBC_2.27 setbuffer F -+GLIBC_2.27 setcontext F -+GLIBC_2.27 setdomainname F -+GLIBC_2.27 setegid F -+GLIBC_2.27 setenv F -+GLIBC_2.27 seteuid F -+GLIBC_2.27 setfsent F -+GLIBC_2.27 setfsgid F -+GLIBC_2.27 setfsuid F -+GLIBC_2.27 setgid F -+GLIBC_2.27 setgrent F -+GLIBC_2.27 setgroups F -+GLIBC_2.27 sethostent F -+GLIBC_2.27 sethostid F -+GLIBC_2.27 sethostname F -+GLIBC_2.27 setipv4sourcefilter F -+GLIBC_2.27 setitimer F -+GLIBC_2.27 setjmp F -+GLIBC_2.27 setlinebuf F -+GLIBC_2.27 setlocale F -+GLIBC_2.27 setlogin F -+GLIBC_2.27 setlogmask F -+GLIBC_2.27 setmntent F -+GLIBC_2.27 setnetent F -+GLIBC_2.27 setnetgrent F -+GLIBC_2.27 setns F -+GLIBC_2.27 setpgid F -+GLIBC_2.27 setpgrp F -+GLIBC_2.27 setpriority F -+GLIBC_2.27 setprotoent F -+GLIBC_2.27 setpwent F -+GLIBC_2.27 setregid F -+GLIBC_2.27 setresgid F -+GLIBC_2.27 setresuid F -+GLIBC_2.27 setreuid F -+GLIBC_2.27 setrlimit F -+GLIBC_2.27 setrlimit64 F -+GLIBC_2.27 setrpcent F -+GLIBC_2.27 setservent F -+GLIBC_2.27 setsgent F -+GLIBC_2.27 setsid F -+GLIBC_2.27 setsockopt F -+GLIBC_2.27 setsourcefilter F -+GLIBC_2.27 setspent F -+GLIBC_2.27 setstate F -+GLIBC_2.27 setstate_r F -+GLIBC_2.27 settimeofday F -+GLIBC_2.27 setttyent F -+GLIBC_2.27 setuid F -+GLIBC_2.27 setusershell F -+GLIBC_2.27 setutent F -+GLIBC_2.27 setutxent F -+GLIBC_2.27 setvbuf F -+GLIBC_2.27 setxattr F -+GLIBC_2.27 sgetsgent F -+GLIBC_2.27 sgetsgent_r F -+GLIBC_2.27 sgetspent F -+GLIBC_2.27 sgetspent_r F -+GLIBC_2.27 shmat F -+GLIBC_2.27 shmctl F -+GLIBC_2.27 shmdt F -+GLIBC_2.27 shmget F -+GLIBC_2.27 shutdown F -+GLIBC_2.27 sigaction F -+GLIBC_2.27 sigaddset F -+GLIBC_2.27 sigaltstack F -+GLIBC_2.27 sigandset F -+GLIBC_2.27 sigblock F -+GLIBC_2.27 sigdelset F -+GLIBC_2.27 sigemptyset F -+GLIBC_2.27 sigfillset F -+GLIBC_2.27 siggetmask F -+GLIBC_2.27 sighold F -+GLIBC_2.27 sigignore F -+GLIBC_2.27 siginterrupt F -+GLIBC_2.27 sigisemptyset F -+GLIBC_2.27 sigismember F -+GLIBC_2.27 siglongjmp F -+GLIBC_2.27 signal F -+GLIBC_2.27 signalfd F -+GLIBC_2.27 sigorset F -+GLIBC_2.27 sigpause F -+GLIBC_2.27 sigpending F -+GLIBC_2.27 sigprocmask F -+GLIBC_2.27 sigqueue F -+GLIBC_2.27 sigrelse F -+GLIBC_2.27 sigreturn F -+GLIBC_2.27 sigset F -+GLIBC_2.27 sigsetmask F -+GLIBC_2.27 sigstack F -+GLIBC_2.27 sigsuspend F -+GLIBC_2.27 sigtimedwait F -+GLIBC_2.27 sigwait F -+GLIBC_2.27 sigwaitinfo F -+GLIBC_2.27 sleep F -+GLIBC_2.27 snprintf F -+GLIBC_2.27 sockatmark F -+GLIBC_2.27 socket F -+GLIBC_2.27 socketpair F -+GLIBC_2.27 splice F -+GLIBC_2.27 sprintf F -+GLIBC_2.27 sprofil F -+GLIBC_2.27 srand F -+GLIBC_2.27 srand48 F -+GLIBC_2.27 srand48_r F -+GLIBC_2.27 srandom F -+GLIBC_2.27 srandom_r F -+GLIBC_2.27 sscanf F -+GLIBC_2.27 ssignal F -+GLIBC_2.27 sstk F -+GLIBC_2.27 statfs F -+GLIBC_2.27 statfs64 F -+GLIBC_2.27 statvfs F -+GLIBC_2.27 statvfs64 F -+GLIBC_2.27 stderr D 0x8 -+GLIBC_2.27 stdin D 0x8 -+GLIBC_2.27 stdout D 0x8 -+GLIBC_2.27 stime F -+GLIBC_2.27 stpcpy F -+GLIBC_2.27 stpncpy F -+GLIBC_2.27 strcasecmp F -+GLIBC_2.27 strcasecmp_l F -+GLIBC_2.27 strcasestr F -+GLIBC_2.27 strcat F -+GLIBC_2.27 strchr F -+GLIBC_2.27 strchrnul F -+GLIBC_2.27 strcmp F -+GLIBC_2.27 strcoll F -+GLIBC_2.27 strcoll_l F -+GLIBC_2.27 strcpy F -+GLIBC_2.27 strcspn F -+GLIBC_2.27 strdup F -+GLIBC_2.27 strerror F -+GLIBC_2.27 strerror_l F -+GLIBC_2.27 strerror_r F -+GLIBC_2.27 strfmon F -+GLIBC_2.27 strfmon_l F -+GLIBC_2.27 strfromd F -+GLIBC_2.27 strfromf F -+GLIBC_2.27 strfromf128 F -+GLIBC_2.27 strfromf32 F -+GLIBC_2.27 strfromf32x F -+GLIBC_2.27 strfromf64 F -+GLIBC_2.27 strfromf64x F -+GLIBC_2.27 strfroml F -+GLIBC_2.27 strfry F -+GLIBC_2.27 strftime F -+GLIBC_2.27 strftime_l F -+GLIBC_2.27 strlen F -+GLIBC_2.27 strncasecmp F -+GLIBC_2.27 strncasecmp_l F -+GLIBC_2.27 strncat F -+GLIBC_2.27 strncmp F -+GLIBC_2.27 strncpy F -+GLIBC_2.27 strndup F -+GLIBC_2.27 strnlen F -+GLIBC_2.27 strpbrk F -+GLIBC_2.27 strptime F -+GLIBC_2.27 strptime_l F -+GLIBC_2.27 strrchr F -+GLIBC_2.27 strsep F -+GLIBC_2.27 strsignal F -+GLIBC_2.27 strspn F -+GLIBC_2.27 strstr F -+GLIBC_2.27 strtod F -+GLIBC_2.27 strtod_l F -+GLIBC_2.27 strtof F -+GLIBC_2.27 strtof128 F -+GLIBC_2.27 strtof128_l F -+GLIBC_2.27 strtof32 F -+GLIBC_2.27 strtof32_l F -+GLIBC_2.27 strtof32x F -+GLIBC_2.27 strtof32x_l F -+GLIBC_2.27 strtof64 F -+GLIBC_2.27 strtof64_l F -+GLIBC_2.27 strtof64x F -+GLIBC_2.27 strtof64x_l F -+GLIBC_2.27 strtof_l F -+GLIBC_2.27 strtoimax F -+GLIBC_2.27 strtok F -+GLIBC_2.27 strtok_r F -+GLIBC_2.27 strtol F -+GLIBC_2.27 strtol_l F -+GLIBC_2.27 strtold F -+GLIBC_2.27 strtold_l F -+GLIBC_2.27 strtoll F -+GLIBC_2.27 strtoll_l F -+GLIBC_2.27 strtoq F -+GLIBC_2.27 strtoul F -+GLIBC_2.27 strtoul_l F -+GLIBC_2.27 strtoull F -+GLIBC_2.27 strtoull_l F -+GLIBC_2.27 strtoumax F -+GLIBC_2.27 strtouq F -+GLIBC_2.27 strverscmp F -+GLIBC_2.27 strxfrm F -+GLIBC_2.27 strxfrm_l F -+GLIBC_2.27 stty F -+GLIBC_2.27 svc_exit F -+GLIBC_2.27 svc_fdset D 0x80 -+GLIBC_2.27 svc_getreq F -+GLIBC_2.27 svc_getreq_common F -+GLIBC_2.27 svc_getreq_poll F -+GLIBC_2.27 svc_getreqset F -+GLIBC_2.27 svc_max_pollfd D 0x4 -+GLIBC_2.27 svc_pollfd D 0x8 -+GLIBC_2.27 svc_register F -+GLIBC_2.27 svc_run F -+GLIBC_2.27 svc_sendreply F -+GLIBC_2.27 svc_unregister F -+GLIBC_2.27 svcauthdes_stats D 0x18 -+GLIBC_2.27 svcerr_auth F -+GLIBC_2.27 svcerr_decode F -+GLIBC_2.27 svcerr_noproc F -+GLIBC_2.27 svcerr_noprog F -+GLIBC_2.27 svcerr_progvers F -+GLIBC_2.27 svcerr_systemerr F -+GLIBC_2.27 svcerr_weakauth F -+GLIBC_2.27 svcfd_create F -+GLIBC_2.27 svcraw_create F -+GLIBC_2.27 svctcp_create F -+GLIBC_2.27 svcudp_bufcreate F -+GLIBC_2.27 svcudp_create F -+GLIBC_2.27 svcudp_enablecache F -+GLIBC_2.27 svcunix_create F -+GLIBC_2.27 svcunixfd_create F -+GLIBC_2.27 swab F -+GLIBC_2.27 swapcontext F -+GLIBC_2.27 swapoff F -+GLIBC_2.27 swapon F -+GLIBC_2.27 swprintf F -+GLIBC_2.27 swscanf F -+GLIBC_2.27 symlink F -+GLIBC_2.27 symlinkat F -+GLIBC_2.27 sync F -+GLIBC_2.27 sync_file_range F -+GLIBC_2.27 syncfs F -+GLIBC_2.27 sys_errlist D 0x2370 -+GLIBC_2.27 sys_nerr D 0x4 -+GLIBC_2.27 sys_sigabbrev D 0x400 -+GLIBC_2.27 sys_siglist D 0x400 -+GLIBC_2.27 syscall F -+GLIBC_2.27 sysconf F -+GLIBC_2.27 sysctl F -+GLIBC_2.27 sysinfo F -+GLIBC_2.27 syslog F -+GLIBC_2.27 system F -+GLIBC_2.27 sysv_signal F -+GLIBC_2.27 tcdrain F -+GLIBC_2.27 tcflow F -+GLIBC_2.27 tcflush F -+GLIBC_2.27 tcgetattr F -+GLIBC_2.27 tcgetpgrp F -+GLIBC_2.27 tcgetsid F -+GLIBC_2.27 tcsendbreak F -+GLIBC_2.27 tcsetattr F -+GLIBC_2.27 tcsetpgrp F -+GLIBC_2.27 tdelete F -+GLIBC_2.27 tdestroy F -+GLIBC_2.27 tee F -+GLIBC_2.27 telldir F -+GLIBC_2.27 tempnam F -+GLIBC_2.27 textdomain F -+GLIBC_2.27 tfind F -+GLIBC_2.27 time F -+GLIBC_2.27 timegm F -+GLIBC_2.27 timelocal F -+GLIBC_2.27 timerfd_create F -+GLIBC_2.27 timerfd_gettime F -+GLIBC_2.27 timerfd_settime F -+GLIBC_2.27 times F -+GLIBC_2.27 timespec_get F -+GLIBC_2.27 timezone D 0x8 -+GLIBC_2.27 tmpfile F -+GLIBC_2.27 tmpfile64 F -+GLIBC_2.27 tmpnam F -+GLIBC_2.27 tmpnam_r F -+GLIBC_2.27 toascii F -+GLIBC_2.27 tolower F -+GLIBC_2.27 tolower_l F -+GLIBC_2.27 toupper F -+GLIBC_2.27 toupper_l F -+GLIBC_2.27 towctrans F -+GLIBC_2.27 towctrans_l F -+GLIBC_2.27 towlower F -+GLIBC_2.27 towlower_l F -+GLIBC_2.27 towupper F -+GLIBC_2.27 towupper_l F -+GLIBC_2.27 tr_break F -+GLIBC_2.27 truncate F -+GLIBC_2.27 truncate64 F -+GLIBC_2.27 tsearch F -+GLIBC_2.27 ttyname F -+GLIBC_2.27 ttyname_r F -+GLIBC_2.27 ttyslot F -+GLIBC_2.27 twalk F -+GLIBC_2.27 tzname D 0x10 -+GLIBC_2.27 tzset F -+GLIBC_2.27 ualarm F -+GLIBC_2.27 ulckpwdf F -+GLIBC_2.27 ulimit F -+GLIBC_2.27 umask F -+GLIBC_2.27 umount F -+GLIBC_2.27 umount2 F -+GLIBC_2.27 uname F -+GLIBC_2.27 ungetc F -+GLIBC_2.27 ungetwc F -+GLIBC_2.27 unlink F -+GLIBC_2.27 unlinkat F -+GLIBC_2.27 unlockpt F -+GLIBC_2.27 unsetenv F -+GLIBC_2.27 unshare F -+GLIBC_2.27 updwtmp F -+GLIBC_2.27 updwtmpx F -+GLIBC_2.27 uselocale F -+GLIBC_2.27 user2netname F -+GLIBC_2.27 usleep F -+GLIBC_2.27 ustat F -+GLIBC_2.27 utime F -+GLIBC_2.27 utimensat F -+GLIBC_2.27 utimes F -+GLIBC_2.27 utmpname F -+GLIBC_2.27 utmpxname F -+GLIBC_2.27 valloc F -+GLIBC_2.27 vasprintf F -+GLIBC_2.27 vdprintf F -+GLIBC_2.27 verr F -+GLIBC_2.27 verrx F -+GLIBC_2.27 versionsort F -+GLIBC_2.27 versionsort64 F -+GLIBC_2.27 vfork F -+GLIBC_2.27 vfprintf F -+GLIBC_2.27 vfscanf F -+GLIBC_2.27 vfwprintf F -+GLIBC_2.27 vfwscanf F -+GLIBC_2.27 vhangup F -+GLIBC_2.27 vlimit F -+GLIBC_2.27 vmsplice F -+GLIBC_2.27 vprintf F -+GLIBC_2.27 vscanf F -+GLIBC_2.27 vsnprintf F -+GLIBC_2.27 vsprintf F -+GLIBC_2.27 vsscanf F -+GLIBC_2.27 vswprintf F -+GLIBC_2.27 vswscanf F -+GLIBC_2.27 vsyslog F -+GLIBC_2.27 vtimes F -+GLIBC_2.27 vwarn F -+GLIBC_2.27 vwarnx F -+GLIBC_2.27 vwprintf F -+GLIBC_2.27 vwscanf F -+GLIBC_2.27 wait F -+GLIBC_2.27 wait3 F -+GLIBC_2.27 wait4 F -+GLIBC_2.27 waitid F -+GLIBC_2.27 waitpid F -+GLIBC_2.27 warn F -+GLIBC_2.27 warnx F -+GLIBC_2.27 wcpcpy F -+GLIBC_2.27 wcpncpy F -+GLIBC_2.27 wcrtomb F -+GLIBC_2.27 wcscasecmp F -+GLIBC_2.27 wcscasecmp_l F -+GLIBC_2.27 wcscat F -+GLIBC_2.27 wcschr F -+GLIBC_2.27 wcschrnul F -+GLIBC_2.27 wcscmp F -+GLIBC_2.27 wcscoll F -+GLIBC_2.27 wcscoll_l F -+GLIBC_2.27 wcscpy F -+GLIBC_2.27 wcscspn F -+GLIBC_2.27 wcsdup F -+GLIBC_2.27 wcsftime F -+GLIBC_2.27 wcsftime_l F -+GLIBC_2.27 wcslen F -+GLIBC_2.27 wcsncasecmp F -+GLIBC_2.27 wcsncasecmp_l F -+GLIBC_2.27 wcsncat F -+GLIBC_2.27 wcsncmp F -+GLIBC_2.27 wcsncpy F -+GLIBC_2.27 wcsnlen F -+GLIBC_2.27 wcsnrtombs F -+GLIBC_2.27 wcspbrk F -+GLIBC_2.27 wcsrchr F -+GLIBC_2.27 wcsrtombs F -+GLIBC_2.27 wcsspn F -+GLIBC_2.27 wcsstr F -+GLIBC_2.27 wcstod F -+GLIBC_2.27 wcstod_l F -+GLIBC_2.27 wcstof F -+GLIBC_2.27 wcstof128 F -+GLIBC_2.27 wcstof128_l F -+GLIBC_2.27 wcstof32 F -+GLIBC_2.27 wcstof32_l F -+GLIBC_2.27 wcstof32x F -+GLIBC_2.27 wcstof32x_l F -+GLIBC_2.27 wcstof64 F -+GLIBC_2.27 wcstof64_l F -+GLIBC_2.27 wcstof64x F -+GLIBC_2.27 wcstof64x_l F -+GLIBC_2.27 wcstof_l F -+GLIBC_2.27 wcstoimax F -+GLIBC_2.27 wcstok F -+GLIBC_2.27 wcstol F -+GLIBC_2.27 wcstol_l F -+GLIBC_2.27 wcstold F -+GLIBC_2.27 wcstold_l F -+GLIBC_2.27 wcstoll F -+GLIBC_2.27 wcstoll_l F -+GLIBC_2.27 wcstombs F -+GLIBC_2.27 wcstoq F -+GLIBC_2.27 wcstoul F -+GLIBC_2.27 wcstoul_l F -+GLIBC_2.27 wcstoull F -+GLIBC_2.27 wcstoull_l F -+GLIBC_2.27 wcstoumax F -+GLIBC_2.27 wcstouq F -+GLIBC_2.27 wcswcs F -+GLIBC_2.27 wcswidth F -+GLIBC_2.27 wcsxfrm F -+GLIBC_2.27 wcsxfrm_l F -+GLIBC_2.27 wctob F -+GLIBC_2.27 wctomb F -+GLIBC_2.27 wctrans F -+GLIBC_2.27 wctrans_l F -+GLIBC_2.27 wctype F -+GLIBC_2.27 wctype_l F -+GLIBC_2.27 wcwidth F -+GLIBC_2.27 wmemchr F -+GLIBC_2.27 wmemcmp F -+GLIBC_2.27 wmemcpy F -+GLIBC_2.27 wmemmove F -+GLIBC_2.27 wmempcpy F -+GLIBC_2.27 wmemset F -+GLIBC_2.27 wordexp F -+GLIBC_2.27 wordfree F -+GLIBC_2.27 wprintf F -+GLIBC_2.27 write F -+GLIBC_2.27 writev F -+GLIBC_2.27 wscanf F -+GLIBC_2.27 xdecrypt F -+GLIBC_2.27 xdr_accepted_reply F -+GLIBC_2.27 xdr_array F -+GLIBC_2.27 xdr_authdes_cred F -+GLIBC_2.27 xdr_authdes_verf F -+GLIBC_2.27 xdr_authunix_parms F -+GLIBC_2.27 xdr_bool F -+GLIBC_2.27 xdr_bytes F -+GLIBC_2.27 xdr_callhdr F -+GLIBC_2.27 xdr_callmsg F -+GLIBC_2.27 xdr_char F -+GLIBC_2.27 xdr_cryptkeyarg F -+GLIBC_2.27 xdr_cryptkeyarg2 F -+GLIBC_2.27 xdr_cryptkeyres F -+GLIBC_2.27 xdr_des_block F -+GLIBC_2.27 xdr_double F -+GLIBC_2.27 xdr_enum F -+GLIBC_2.27 xdr_float F -+GLIBC_2.27 xdr_free F -+GLIBC_2.27 xdr_getcredres F -+GLIBC_2.27 xdr_hyper F -+GLIBC_2.27 xdr_int F -+GLIBC_2.27 xdr_int16_t F -+GLIBC_2.27 xdr_int32_t F -+GLIBC_2.27 xdr_int64_t F -+GLIBC_2.27 xdr_int8_t F -+GLIBC_2.27 xdr_key_netstarg F -+GLIBC_2.27 xdr_key_netstres F -+GLIBC_2.27 xdr_keybuf F -+GLIBC_2.27 xdr_keystatus F -+GLIBC_2.27 xdr_long F -+GLIBC_2.27 xdr_longlong_t F -+GLIBC_2.27 xdr_netnamestr F -+GLIBC_2.27 xdr_netobj F -+GLIBC_2.27 xdr_opaque F -+GLIBC_2.27 xdr_opaque_auth F -+GLIBC_2.27 xdr_pmap F -+GLIBC_2.27 xdr_pmaplist F -+GLIBC_2.27 xdr_pointer F -+GLIBC_2.27 xdr_quad_t F -+GLIBC_2.27 xdr_reference F -+GLIBC_2.27 xdr_rejected_reply F -+GLIBC_2.27 xdr_replymsg F -+GLIBC_2.27 xdr_rmtcall_args F -+GLIBC_2.27 xdr_rmtcallres F -+GLIBC_2.27 xdr_short F -+GLIBC_2.27 xdr_sizeof F -+GLIBC_2.27 xdr_string F -+GLIBC_2.27 xdr_u_char F -+GLIBC_2.27 xdr_u_hyper F -+GLIBC_2.27 xdr_u_int F -+GLIBC_2.27 xdr_u_long F -+GLIBC_2.27 xdr_u_longlong_t F -+GLIBC_2.27 xdr_u_quad_t F -+GLIBC_2.27 xdr_u_short F -+GLIBC_2.27 xdr_uint16_t F -+GLIBC_2.27 xdr_uint32_t F -+GLIBC_2.27 xdr_uint64_t F -+GLIBC_2.27 xdr_uint8_t F -+GLIBC_2.27 xdr_union F -+GLIBC_2.27 xdr_unixcred F -+GLIBC_2.27 xdr_vector F -+GLIBC_2.27 xdr_void F -+GLIBC_2.27 xdr_wrapstring F -+GLIBC_2.27 xdrmem_create F -+GLIBC_2.27 xdrrec_create F -+GLIBC_2.27 xdrrec_endofrecord F -+GLIBC_2.27 xdrrec_eof F -+GLIBC_2.27 xdrrec_skiprecord F -+GLIBC_2.27 xdrstdio_create F -+GLIBC_2.27 xencrypt F -+GLIBC_2.27 xprt_register F -+GLIBC_2.27 xprt_unregister F -+GLIBC_2.28 fcntl64 F -+GLIBC_2.28 renameat2 F -+GLIBC_2.28 statx F -+GLIBC_2.28 thrd_current F -+GLIBC_2.28 thrd_equal F -+GLIBC_2.28 thrd_sleep F -+GLIBC_2.28 thrd_yield F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libcrypt.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libcrypt.abilist -new file mode 100644 -index 00000000..9484dca7 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libcrypt.abilist -@@ -0,0 +1,7 @@ -+GLIBC_2.27 crypt F -+GLIBC_2.27 crypt_r F -+GLIBC_2.27 encrypt F -+GLIBC_2.27 encrypt_r F -+GLIBC_2.27 fcrypt F -+GLIBC_2.27 setkey F -+GLIBC_2.27 setkey_r F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libdl.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libdl.abilist -new file mode 100644 -index 00000000..16adcae5 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libdl.abilist -@@ -0,0 +1,9 @@ -+GLIBC_2.27 dladdr F -+GLIBC_2.27 dladdr1 F -+GLIBC_2.27 dlclose F -+GLIBC_2.27 dlerror F -+GLIBC_2.27 dlinfo F -+GLIBC_2.27 dlmopen F -+GLIBC_2.27 dlopen F -+GLIBC_2.27 dlsym F -+GLIBC_2.27 dlvsym F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libm.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libm.abilist -new file mode 100644 -index 00000000..361fce20 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libm.abilist -@@ -0,0 +1,1021 @@ -+GLIBC_2.27 __acos_finite F -+GLIBC_2.27 __acosf_finite F -+GLIBC_2.27 __acosh_finite F -+GLIBC_2.27 __acoshf_finite F -+GLIBC_2.27 __acoshl_finite F -+GLIBC_2.27 __acosl_finite F -+GLIBC_2.27 __asin_finite F -+GLIBC_2.27 __asinf_finite F -+GLIBC_2.27 __asinl_finite F -+GLIBC_2.27 __atan2_finite F -+GLIBC_2.27 __atan2f_finite F -+GLIBC_2.27 __atan2l_finite F -+GLIBC_2.27 __atanh_finite F -+GLIBC_2.27 __atanhf_finite F -+GLIBC_2.27 __atanhl_finite F -+GLIBC_2.27 __clog10 F -+GLIBC_2.27 __clog10f F -+GLIBC_2.27 __clog10l F -+GLIBC_2.27 __cosh_finite F -+GLIBC_2.27 __coshf_finite F -+GLIBC_2.27 __coshl_finite F -+GLIBC_2.27 __exp10_finite F -+GLIBC_2.27 __exp10f_finite F -+GLIBC_2.27 __exp10l_finite F -+GLIBC_2.27 __exp2_finite F -+GLIBC_2.27 __exp2f_finite F -+GLIBC_2.27 __exp2l_finite F -+GLIBC_2.27 __exp_finite F -+GLIBC_2.27 __expf_finite F -+GLIBC_2.27 __expl_finite F -+GLIBC_2.27 __finite F -+GLIBC_2.27 __finitef F -+GLIBC_2.27 __finitel F -+GLIBC_2.27 __fmod_finite F -+GLIBC_2.27 __fmodf_finite F -+GLIBC_2.27 __fmodl_finite F -+GLIBC_2.27 __fpclassify F -+GLIBC_2.27 __fpclassifyf F -+GLIBC_2.27 __fpclassifyl F -+GLIBC_2.27 __gamma_r_finite F -+GLIBC_2.27 __gammaf_r_finite F -+GLIBC_2.27 __gammal_r_finite F -+GLIBC_2.27 __hypot_finite F -+GLIBC_2.27 __hypotf_finite F -+GLIBC_2.27 __hypotl_finite F -+GLIBC_2.27 __iseqsig F -+GLIBC_2.27 __iseqsigf F -+GLIBC_2.27 __iseqsigl F -+GLIBC_2.27 __issignaling F -+GLIBC_2.27 __issignalingf F -+GLIBC_2.27 __issignalingl F -+GLIBC_2.27 __j0_finite F -+GLIBC_2.27 __j0f_finite F -+GLIBC_2.27 __j0l_finite F -+GLIBC_2.27 __j1_finite F -+GLIBC_2.27 __j1f_finite F -+GLIBC_2.27 __j1l_finite F -+GLIBC_2.27 __jn_finite F -+GLIBC_2.27 __jnf_finite F -+GLIBC_2.27 __jnl_finite F -+GLIBC_2.27 __lgamma_r_finite F -+GLIBC_2.27 __lgammaf_r_finite F -+GLIBC_2.27 __lgammal_r_finite F -+GLIBC_2.27 __log10_finite F -+GLIBC_2.27 __log10f_finite F -+GLIBC_2.27 __log10l_finite F -+GLIBC_2.27 __log2_finite F -+GLIBC_2.27 __log2f_finite F -+GLIBC_2.27 __log2l_finite F -+GLIBC_2.27 __log_finite F -+GLIBC_2.27 __logf_finite F -+GLIBC_2.27 __logl_finite F -+GLIBC_2.27 __pow_finite F -+GLIBC_2.27 __powf_finite F -+GLIBC_2.27 __powl_finite F -+GLIBC_2.27 __remainder_finite F -+GLIBC_2.27 __remainderf_finite F -+GLIBC_2.27 __remainderl_finite F -+GLIBC_2.27 __scalb_finite F -+GLIBC_2.27 __scalbf_finite F -+GLIBC_2.27 __scalbl_finite F -+GLIBC_2.27 __signbit F -+GLIBC_2.27 __signbitf F -+GLIBC_2.27 __signbitl F -+GLIBC_2.27 __signgam D 0x4 -+GLIBC_2.27 __sinh_finite F -+GLIBC_2.27 __sinhf_finite F -+GLIBC_2.27 __sinhl_finite F -+GLIBC_2.27 __sqrt_finite F -+GLIBC_2.27 __sqrtf_finite F -+GLIBC_2.27 __sqrtl_finite F -+GLIBC_2.27 __y0_finite F -+GLIBC_2.27 __y0f_finite F -+GLIBC_2.27 __y0l_finite F -+GLIBC_2.27 __y1_finite F -+GLIBC_2.27 __y1f_finite F -+GLIBC_2.27 __y1l_finite F -+GLIBC_2.27 __yn_finite F -+GLIBC_2.27 __ynf_finite F -+GLIBC_2.27 __ynl_finite F -+GLIBC_2.27 acos F -+GLIBC_2.27 acosf F -+GLIBC_2.27 acosf128 F -+GLIBC_2.27 acosf32 F -+GLIBC_2.27 acosf32x F -+GLIBC_2.27 acosf64 F -+GLIBC_2.27 acosf64x F -+GLIBC_2.27 acosh F -+GLIBC_2.27 acoshf F -+GLIBC_2.27 acoshf128 F -+GLIBC_2.27 acoshf32 F -+GLIBC_2.27 acoshf32x F -+GLIBC_2.27 acoshf64 F -+GLIBC_2.27 acoshf64x F -+GLIBC_2.27 acoshl F -+GLIBC_2.27 acosl F -+GLIBC_2.27 asin F -+GLIBC_2.27 asinf F -+GLIBC_2.27 asinf128 F -+GLIBC_2.27 asinf32 F -+GLIBC_2.27 asinf32x F -+GLIBC_2.27 asinf64 F -+GLIBC_2.27 asinf64x F -+GLIBC_2.27 asinh F -+GLIBC_2.27 asinhf F -+GLIBC_2.27 asinhf128 F -+GLIBC_2.27 asinhf32 F -+GLIBC_2.27 asinhf32x F -+GLIBC_2.27 asinhf64 F -+GLIBC_2.27 asinhf64x F -+GLIBC_2.27 asinhl F -+GLIBC_2.27 asinl F -+GLIBC_2.27 atan F -+GLIBC_2.27 atan2 F -+GLIBC_2.27 atan2f F -+GLIBC_2.27 atan2f128 F -+GLIBC_2.27 atan2f32 F -+GLIBC_2.27 atan2f32x F -+GLIBC_2.27 atan2f64 F -+GLIBC_2.27 atan2f64x F -+GLIBC_2.27 atan2l F -+GLIBC_2.27 atanf F -+GLIBC_2.27 atanf128 F -+GLIBC_2.27 atanf32 F -+GLIBC_2.27 atanf32x F -+GLIBC_2.27 atanf64 F -+GLIBC_2.27 atanf64x F -+GLIBC_2.27 atanh F -+GLIBC_2.27 atanhf F -+GLIBC_2.27 atanhf128 F -+GLIBC_2.27 atanhf32 F -+GLIBC_2.27 atanhf32x F -+GLIBC_2.27 atanhf64 F -+GLIBC_2.27 atanhf64x F -+GLIBC_2.27 atanhl F -+GLIBC_2.27 atanl F -+GLIBC_2.27 cabs F -+GLIBC_2.27 cabsf F -+GLIBC_2.27 cabsf128 F -+GLIBC_2.27 cabsf32 F -+GLIBC_2.27 cabsf32x F -+GLIBC_2.27 cabsf64 F -+GLIBC_2.27 cabsf64x F -+GLIBC_2.27 cabsl F -+GLIBC_2.27 cacos F -+GLIBC_2.27 cacosf F -+GLIBC_2.27 cacosf128 F -+GLIBC_2.27 cacosf32 F -+GLIBC_2.27 cacosf32x F -+GLIBC_2.27 cacosf64 F -+GLIBC_2.27 cacosf64x F -+GLIBC_2.27 cacosh F -+GLIBC_2.27 cacoshf F -+GLIBC_2.27 cacoshf128 F -+GLIBC_2.27 cacoshf32 F -+GLIBC_2.27 cacoshf32x F -+GLIBC_2.27 cacoshf64 F -+GLIBC_2.27 cacoshf64x F -+GLIBC_2.27 cacoshl F -+GLIBC_2.27 cacosl F -+GLIBC_2.27 canonicalize F -+GLIBC_2.27 canonicalizef F -+GLIBC_2.27 canonicalizef128 F -+GLIBC_2.27 canonicalizef32 F -+GLIBC_2.27 canonicalizef32x F -+GLIBC_2.27 canonicalizef64 F -+GLIBC_2.27 canonicalizef64x F -+GLIBC_2.27 canonicalizel F -+GLIBC_2.27 carg F -+GLIBC_2.27 cargf F -+GLIBC_2.27 cargf128 F -+GLIBC_2.27 cargf32 F -+GLIBC_2.27 cargf32x F -+GLIBC_2.27 cargf64 F -+GLIBC_2.27 cargf64x F -+GLIBC_2.27 cargl F -+GLIBC_2.27 casin F -+GLIBC_2.27 casinf F -+GLIBC_2.27 casinf128 F -+GLIBC_2.27 casinf32 F -+GLIBC_2.27 casinf32x F -+GLIBC_2.27 casinf64 F -+GLIBC_2.27 casinf64x F -+GLIBC_2.27 casinh F -+GLIBC_2.27 casinhf F -+GLIBC_2.27 casinhf128 F -+GLIBC_2.27 casinhf32 F -+GLIBC_2.27 casinhf32x F -+GLIBC_2.27 casinhf64 F -+GLIBC_2.27 casinhf64x F -+GLIBC_2.27 casinhl F -+GLIBC_2.27 casinl F -+GLIBC_2.27 catan F -+GLIBC_2.27 catanf F -+GLIBC_2.27 catanf128 F -+GLIBC_2.27 catanf32 F -+GLIBC_2.27 catanf32x F -+GLIBC_2.27 catanf64 F -+GLIBC_2.27 catanf64x F -+GLIBC_2.27 catanh F -+GLIBC_2.27 catanhf F -+GLIBC_2.27 catanhf128 F -+GLIBC_2.27 catanhf32 F -+GLIBC_2.27 catanhf32x F -+GLIBC_2.27 catanhf64 F -+GLIBC_2.27 catanhf64x F -+GLIBC_2.27 catanhl F -+GLIBC_2.27 catanl F -+GLIBC_2.27 cbrt F -+GLIBC_2.27 cbrtf F -+GLIBC_2.27 cbrtf128 F -+GLIBC_2.27 cbrtf32 F -+GLIBC_2.27 cbrtf32x F -+GLIBC_2.27 cbrtf64 F -+GLIBC_2.27 cbrtf64x F -+GLIBC_2.27 cbrtl F -+GLIBC_2.27 ccos F -+GLIBC_2.27 ccosf F -+GLIBC_2.27 ccosf128 F -+GLIBC_2.27 ccosf32 F -+GLIBC_2.27 ccosf32x F -+GLIBC_2.27 ccosf64 F -+GLIBC_2.27 ccosf64x F -+GLIBC_2.27 ccosh F -+GLIBC_2.27 ccoshf F -+GLIBC_2.27 ccoshf128 F -+GLIBC_2.27 ccoshf32 F -+GLIBC_2.27 ccoshf32x F -+GLIBC_2.27 ccoshf64 F -+GLIBC_2.27 ccoshf64x F -+GLIBC_2.27 ccoshl F -+GLIBC_2.27 ccosl F -+GLIBC_2.27 ceil F -+GLIBC_2.27 ceilf F -+GLIBC_2.27 ceilf128 F -+GLIBC_2.27 ceilf32 F -+GLIBC_2.27 ceilf32x F -+GLIBC_2.27 ceilf64 F -+GLIBC_2.27 ceilf64x F -+GLIBC_2.27 ceill F -+GLIBC_2.27 cexp F -+GLIBC_2.27 cexpf F -+GLIBC_2.27 cexpf128 F -+GLIBC_2.27 cexpf32 F -+GLIBC_2.27 cexpf32x F -+GLIBC_2.27 cexpf64 F -+GLIBC_2.27 cexpf64x F -+GLIBC_2.27 cexpl F -+GLIBC_2.27 cimag F -+GLIBC_2.27 cimagf F -+GLIBC_2.27 cimagf128 F -+GLIBC_2.27 cimagf32 F -+GLIBC_2.27 cimagf32x F -+GLIBC_2.27 cimagf64 F -+GLIBC_2.27 cimagf64x F -+GLIBC_2.27 cimagl F -+GLIBC_2.27 clog F -+GLIBC_2.27 clog10 F -+GLIBC_2.27 clog10f F -+GLIBC_2.27 clog10f128 F -+GLIBC_2.27 clog10f32 F -+GLIBC_2.27 clog10f32x F -+GLIBC_2.27 clog10f64 F -+GLIBC_2.27 clog10f64x F -+GLIBC_2.27 clog10l F -+GLIBC_2.27 clogf F -+GLIBC_2.27 clogf128 F -+GLIBC_2.27 clogf32 F -+GLIBC_2.27 clogf32x F -+GLIBC_2.27 clogf64 F -+GLIBC_2.27 clogf64x F -+GLIBC_2.27 clogl F -+GLIBC_2.27 conj F -+GLIBC_2.27 conjf F -+GLIBC_2.27 conjf128 F -+GLIBC_2.27 conjf32 F -+GLIBC_2.27 conjf32x F -+GLIBC_2.27 conjf64 F -+GLIBC_2.27 conjf64x F -+GLIBC_2.27 conjl F -+GLIBC_2.27 copysign F -+GLIBC_2.27 copysignf F -+GLIBC_2.27 copysignf128 F -+GLIBC_2.27 copysignf32 F -+GLIBC_2.27 copysignf32x F -+GLIBC_2.27 copysignf64 F -+GLIBC_2.27 copysignf64x F -+GLIBC_2.27 copysignl F -+GLIBC_2.27 cos F -+GLIBC_2.27 cosf F -+GLIBC_2.27 cosf128 F -+GLIBC_2.27 cosf32 F -+GLIBC_2.27 cosf32x F -+GLIBC_2.27 cosf64 F -+GLIBC_2.27 cosf64x F -+GLIBC_2.27 cosh F -+GLIBC_2.27 coshf F -+GLIBC_2.27 coshf128 F -+GLIBC_2.27 coshf32 F -+GLIBC_2.27 coshf32x F -+GLIBC_2.27 coshf64 F -+GLIBC_2.27 coshf64x F -+GLIBC_2.27 coshl F -+GLIBC_2.27 cosl F -+GLIBC_2.27 cpow F -+GLIBC_2.27 cpowf F -+GLIBC_2.27 cpowf128 F -+GLIBC_2.27 cpowf32 F -+GLIBC_2.27 cpowf32x F -+GLIBC_2.27 cpowf64 F -+GLIBC_2.27 cpowf64x F -+GLIBC_2.27 cpowl F -+GLIBC_2.27 cproj F -+GLIBC_2.27 cprojf F -+GLIBC_2.27 cprojf128 F -+GLIBC_2.27 cprojf32 F -+GLIBC_2.27 cprojf32x F -+GLIBC_2.27 cprojf64 F -+GLIBC_2.27 cprojf64x F -+GLIBC_2.27 cprojl F -+GLIBC_2.27 creal F -+GLIBC_2.27 crealf F -+GLIBC_2.27 crealf128 F -+GLIBC_2.27 crealf32 F -+GLIBC_2.27 crealf32x F -+GLIBC_2.27 crealf64 F -+GLIBC_2.27 crealf64x F -+GLIBC_2.27 creall F -+GLIBC_2.27 csin F -+GLIBC_2.27 csinf F -+GLIBC_2.27 csinf128 F -+GLIBC_2.27 csinf32 F -+GLIBC_2.27 csinf32x F -+GLIBC_2.27 csinf64 F -+GLIBC_2.27 csinf64x F -+GLIBC_2.27 csinh F -+GLIBC_2.27 csinhf F -+GLIBC_2.27 csinhf128 F -+GLIBC_2.27 csinhf32 F -+GLIBC_2.27 csinhf32x F -+GLIBC_2.27 csinhf64 F -+GLIBC_2.27 csinhf64x F -+GLIBC_2.27 csinhl F -+GLIBC_2.27 csinl F -+GLIBC_2.27 csqrt F -+GLIBC_2.27 csqrtf F -+GLIBC_2.27 csqrtf128 F -+GLIBC_2.27 csqrtf32 F -+GLIBC_2.27 csqrtf32x F -+GLIBC_2.27 csqrtf64 F -+GLIBC_2.27 csqrtf64x F -+GLIBC_2.27 csqrtl F -+GLIBC_2.27 ctan F -+GLIBC_2.27 ctanf F -+GLIBC_2.27 ctanf128 F -+GLIBC_2.27 ctanf32 F -+GLIBC_2.27 ctanf32x F -+GLIBC_2.27 ctanf64 F -+GLIBC_2.27 ctanf64x F -+GLIBC_2.27 ctanh F -+GLIBC_2.27 ctanhf F -+GLIBC_2.27 ctanhf128 F -+GLIBC_2.27 ctanhf32 F -+GLIBC_2.27 ctanhf32x F -+GLIBC_2.27 ctanhf64 F -+GLIBC_2.27 ctanhf64x F -+GLIBC_2.27 ctanhl F -+GLIBC_2.27 ctanl F -+GLIBC_2.27 drem F -+GLIBC_2.27 dremf F -+GLIBC_2.27 dreml F -+GLIBC_2.27 erf F -+GLIBC_2.27 erfc F -+GLIBC_2.27 erfcf F -+GLIBC_2.27 erfcf128 F -+GLIBC_2.27 erfcf32 F -+GLIBC_2.27 erfcf32x F -+GLIBC_2.27 erfcf64 F -+GLIBC_2.27 erfcf64x F -+GLIBC_2.27 erfcl F -+GLIBC_2.27 erff F -+GLIBC_2.27 erff128 F -+GLIBC_2.27 erff32 F -+GLIBC_2.27 erff32x F -+GLIBC_2.27 erff64 F -+GLIBC_2.27 erff64x F -+GLIBC_2.27 erfl F -+GLIBC_2.27 exp F -+GLIBC_2.27 exp10 F -+GLIBC_2.27 exp10f F -+GLIBC_2.27 exp10f128 F -+GLIBC_2.27 exp10f32 F -+GLIBC_2.27 exp10f32x F -+GLIBC_2.27 exp10f64 F -+GLIBC_2.27 exp10f64x F -+GLIBC_2.27 exp10l F -+GLIBC_2.27 exp2 F -+GLIBC_2.27 exp2f F -+GLIBC_2.27 exp2f128 F -+GLIBC_2.27 exp2f32 F -+GLIBC_2.27 exp2f32x F -+GLIBC_2.27 exp2f64 F -+GLIBC_2.27 exp2f64x F -+GLIBC_2.27 exp2l F -+GLIBC_2.27 expf F -+GLIBC_2.27 expf128 F -+GLIBC_2.27 expf32 F -+GLIBC_2.27 expf32x F -+GLIBC_2.27 expf64 F -+GLIBC_2.27 expf64x F -+GLIBC_2.27 expl F -+GLIBC_2.27 expm1 F -+GLIBC_2.27 expm1f F -+GLIBC_2.27 expm1f128 F -+GLIBC_2.27 expm1f32 F -+GLIBC_2.27 expm1f32x F -+GLIBC_2.27 expm1f64 F -+GLIBC_2.27 expm1f64x F -+GLIBC_2.27 expm1l F -+GLIBC_2.27 fabs F -+GLIBC_2.27 fabsf F -+GLIBC_2.27 fabsf128 F -+GLIBC_2.27 fabsf32 F -+GLIBC_2.27 fabsf32x F -+GLIBC_2.27 fabsf64 F -+GLIBC_2.27 fabsf64x F -+GLIBC_2.27 fabsl F -+GLIBC_2.27 fdim F -+GLIBC_2.27 fdimf F -+GLIBC_2.27 fdimf128 F -+GLIBC_2.27 fdimf32 F -+GLIBC_2.27 fdimf32x F -+GLIBC_2.27 fdimf64 F -+GLIBC_2.27 fdimf64x F -+GLIBC_2.27 fdiml F -+GLIBC_2.27 feclearexcept F -+GLIBC_2.27 fedisableexcept F -+GLIBC_2.27 feenableexcept F -+GLIBC_2.27 fegetenv F -+GLIBC_2.27 fegetexcept F -+GLIBC_2.27 fegetexceptflag F -+GLIBC_2.27 fegetmode F -+GLIBC_2.27 fegetround F -+GLIBC_2.27 feholdexcept F -+GLIBC_2.27 feraiseexcept F -+GLIBC_2.27 fesetenv F -+GLIBC_2.27 fesetexcept F -+GLIBC_2.27 fesetexceptflag F -+GLIBC_2.27 fesetmode F -+GLIBC_2.27 fesetround F -+GLIBC_2.27 fetestexcept F -+GLIBC_2.27 fetestexceptflag F -+GLIBC_2.27 feupdateenv F -+GLIBC_2.27 finite F -+GLIBC_2.27 finitef F -+GLIBC_2.27 finitel F -+GLIBC_2.27 floor F -+GLIBC_2.27 floorf F -+GLIBC_2.27 floorf128 F -+GLIBC_2.27 floorf32 F -+GLIBC_2.27 floorf32x F -+GLIBC_2.27 floorf64 F -+GLIBC_2.27 floorf64x F -+GLIBC_2.27 floorl F -+GLIBC_2.27 fma F -+GLIBC_2.27 fmaf F -+GLIBC_2.27 fmaf128 F -+GLIBC_2.27 fmaf32 F -+GLIBC_2.27 fmaf32x F -+GLIBC_2.27 fmaf64 F -+GLIBC_2.27 fmaf64x F -+GLIBC_2.27 fmal F -+GLIBC_2.27 fmax F -+GLIBC_2.27 fmaxf F -+GLIBC_2.27 fmaxf128 F -+GLIBC_2.27 fmaxf32 F -+GLIBC_2.27 fmaxf32x F -+GLIBC_2.27 fmaxf64 F -+GLIBC_2.27 fmaxf64x F -+GLIBC_2.27 fmaxl F -+GLIBC_2.27 fmaxmag F -+GLIBC_2.27 fmaxmagf F -+GLIBC_2.27 fmaxmagf128 F -+GLIBC_2.27 fmaxmagf32 F -+GLIBC_2.27 fmaxmagf32x F -+GLIBC_2.27 fmaxmagf64 F -+GLIBC_2.27 fmaxmagf64x F -+GLIBC_2.27 fmaxmagl F -+GLIBC_2.27 fmin F -+GLIBC_2.27 fminf F -+GLIBC_2.27 fminf128 F -+GLIBC_2.27 fminf32 F -+GLIBC_2.27 fminf32x F -+GLIBC_2.27 fminf64 F -+GLIBC_2.27 fminf64x F -+GLIBC_2.27 fminl F -+GLIBC_2.27 fminmag F -+GLIBC_2.27 fminmagf F -+GLIBC_2.27 fminmagf128 F -+GLIBC_2.27 fminmagf32 F -+GLIBC_2.27 fminmagf32x F -+GLIBC_2.27 fminmagf64 F -+GLIBC_2.27 fminmagf64x F -+GLIBC_2.27 fminmagl F -+GLIBC_2.27 fmod F -+GLIBC_2.27 fmodf F -+GLIBC_2.27 fmodf128 F -+GLIBC_2.27 fmodf32 F -+GLIBC_2.27 fmodf32x F -+GLIBC_2.27 fmodf64 F -+GLIBC_2.27 fmodf64x F -+GLIBC_2.27 fmodl F -+GLIBC_2.27 frexp F -+GLIBC_2.27 frexpf F -+GLIBC_2.27 frexpf128 F -+GLIBC_2.27 frexpf32 F -+GLIBC_2.27 frexpf32x F -+GLIBC_2.27 frexpf64 F -+GLIBC_2.27 frexpf64x F -+GLIBC_2.27 frexpl F -+GLIBC_2.27 fromfp F -+GLIBC_2.27 fromfpf F -+GLIBC_2.27 fromfpf128 F -+GLIBC_2.27 fromfpf32 F -+GLIBC_2.27 fromfpf32x F -+GLIBC_2.27 fromfpf64 F -+GLIBC_2.27 fromfpf64x F -+GLIBC_2.27 fromfpl F -+GLIBC_2.27 fromfpx F -+GLIBC_2.27 fromfpxf F -+GLIBC_2.27 fromfpxf128 F -+GLIBC_2.27 fromfpxf32 F -+GLIBC_2.27 fromfpxf32x F -+GLIBC_2.27 fromfpxf64 F -+GLIBC_2.27 fromfpxf64x F -+GLIBC_2.27 fromfpxl F -+GLIBC_2.27 gamma F -+GLIBC_2.27 gammaf F -+GLIBC_2.27 gammal F -+GLIBC_2.27 getpayload F -+GLIBC_2.27 getpayloadf F -+GLIBC_2.27 getpayloadf128 F -+GLIBC_2.27 getpayloadf32 F -+GLIBC_2.27 getpayloadf32x F -+GLIBC_2.27 getpayloadf64 F -+GLIBC_2.27 getpayloadf64x F -+GLIBC_2.27 getpayloadl F -+GLIBC_2.27 hypot F -+GLIBC_2.27 hypotf F -+GLIBC_2.27 hypotf128 F -+GLIBC_2.27 hypotf32 F -+GLIBC_2.27 hypotf32x F -+GLIBC_2.27 hypotf64 F -+GLIBC_2.27 hypotf64x F -+GLIBC_2.27 hypotl F -+GLIBC_2.27 ilogb F -+GLIBC_2.27 ilogbf F -+GLIBC_2.27 ilogbf128 F -+GLIBC_2.27 ilogbf32 F -+GLIBC_2.27 ilogbf32x F -+GLIBC_2.27 ilogbf64 F -+GLIBC_2.27 ilogbf64x F -+GLIBC_2.27 ilogbl F -+GLIBC_2.27 j0 F -+GLIBC_2.27 j0f F -+GLIBC_2.27 j0f128 F -+GLIBC_2.27 j0f32 F -+GLIBC_2.27 j0f32x F -+GLIBC_2.27 j0f64 F -+GLIBC_2.27 j0f64x F -+GLIBC_2.27 j0l F -+GLIBC_2.27 j1 F -+GLIBC_2.27 j1f F -+GLIBC_2.27 j1f128 F -+GLIBC_2.27 j1f32 F -+GLIBC_2.27 j1f32x F -+GLIBC_2.27 j1f64 F -+GLIBC_2.27 j1f64x F -+GLIBC_2.27 j1l F -+GLIBC_2.27 jn F -+GLIBC_2.27 jnf F -+GLIBC_2.27 jnf128 F -+GLIBC_2.27 jnf32 F -+GLIBC_2.27 jnf32x F -+GLIBC_2.27 jnf64 F -+GLIBC_2.27 jnf64x F -+GLIBC_2.27 jnl F -+GLIBC_2.27 ldexp F -+GLIBC_2.27 ldexpf F -+GLIBC_2.27 ldexpf128 F -+GLIBC_2.27 ldexpf32 F -+GLIBC_2.27 ldexpf32x F -+GLIBC_2.27 ldexpf64 F -+GLIBC_2.27 ldexpf64x F -+GLIBC_2.27 ldexpl F -+GLIBC_2.27 lgamma F -+GLIBC_2.27 lgamma_r F -+GLIBC_2.27 lgammaf F -+GLIBC_2.27 lgammaf128 F -+GLIBC_2.27 lgammaf128_r F -+GLIBC_2.27 lgammaf32 F -+GLIBC_2.27 lgammaf32_r F -+GLIBC_2.27 lgammaf32x F -+GLIBC_2.27 lgammaf32x_r F -+GLIBC_2.27 lgammaf64 F -+GLIBC_2.27 lgammaf64_r F -+GLIBC_2.27 lgammaf64x F -+GLIBC_2.27 lgammaf64x_r F -+GLIBC_2.27 lgammaf_r F -+GLIBC_2.27 lgammal F -+GLIBC_2.27 lgammal_r F -+GLIBC_2.27 llogb F -+GLIBC_2.27 llogbf F -+GLIBC_2.27 llogbf128 F -+GLIBC_2.27 llogbf32 F -+GLIBC_2.27 llogbf32x F -+GLIBC_2.27 llogbf64 F -+GLIBC_2.27 llogbf64x F -+GLIBC_2.27 llogbl F -+GLIBC_2.27 llrint F -+GLIBC_2.27 llrintf F -+GLIBC_2.27 llrintf128 F -+GLIBC_2.27 llrintf32 F -+GLIBC_2.27 llrintf32x F -+GLIBC_2.27 llrintf64 F -+GLIBC_2.27 llrintf64x F -+GLIBC_2.27 llrintl F -+GLIBC_2.27 llround F -+GLIBC_2.27 llroundf F -+GLIBC_2.27 llroundf128 F -+GLIBC_2.27 llroundf32 F -+GLIBC_2.27 llroundf32x F -+GLIBC_2.27 llroundf64 F -+GLIBC_2.27 llroundf64x F -+GLIBC_2.27 llroundl F -+GLIBC_2.27 log F -+GLIBC_2.27 log10 F -+GLIBC_2.27 log10f F -+GLIBC_2.27 log10f128 F -+GLIBC_2.27 log10f32 F -+GLIBC_2.27 log10f32x F -+GLIBC_2.27 log10f64 F -+GLIBC_2.27 log10f64x F -+GLIBC_2.27 log10l F -+GLIBC_2.27 log1p F -+GLIBC_2.27 log1pf F -+GLIBC_2.27 log1pf128 F -+GLIBC_2.27 log1pf32 F -+GLIBC_2.27 log1pf32x F -+GLIBC_2.27 log1pf64 F -+GLIBC_2.27 log1pf64x F -+GLIBC_2.27 log1pl F -+GLIBC_2.27 log2 F -+GLIBC_2.27 log2f F -+GLIBC_2.27 log2f128 F -+GLIBC_2.27 log2f32 F -+GLIBC_2.27 log2f32x F -+GLIBC_2.27 log2f64 F -+GLIBC_2.27 log2f64x F -+GLIBC_2.27 log2l F -+GLIBC_2.27 logb F -+GLIBC_2.27 logbf F -+GLIBC_2.27 logbf128 F -+GLIBC_2.27 logbf32 F -+GLIBC_2.27 logbf32x F -+GLIBC_2.27 logbf64 F -+GLIBC_2.27 logbf64x F -+GLIBC_2.27 logbl F -+GLIBC_2.27 logf F -+GLIBC_2.27 logf128 F -+GLIBC_2.27 logf32 F -+GLIBC_2.27 logf32x F -+GLIBC_2.27 logf64 F -+GLIBC_2.27 logf64x F -+GLIBC_2.27 logl F -+GLIBC_2.27 lrint F -+GLIBC_2.27 lrintf F -+GLIBC_2.27 lrintf128 F -+GLIBC_2.27 lrintf32 F -+GLIBC_2.27 lrintf32x F -+GLIBC_2.27 lrintf64 F -+GLIBC_2.27 lrintf64x F -+GLIBC_2.27 lrintl F -+GLIBC_2.27 lround F -+GLIBC_2.27 lroundf F -+GLIBC_2.27 lroundf128 F -+GLIBC_2.27 lroundf32 F -+GLIBC_2.27 lroundf32x F -+GLIBC_2.27 lroundf64 F -+GLIBC_2.27 lroundf64x F -+GLIBC_2.27 lroundl F -+GLIBC_2.27 modf F -+GLIBC_2.27 modff F -+GLIBC_2.27 modff128 F -+GLIBC_2.27 modff32 F -+GLIBC_2.27 modff32x F -+GLIBC_2.27 modff64 F -+GLIBC_2.27 modff64x F -+GLIBC_2.27 modfl F -+GLIBC_2.27 nan F -+GLIBC_2.27 nanf F -+GLIBC_2.27 nanf128 F -+GLIBC_2.27 nanf32 F -+GLIBC_2.27 nanf32x F -+GLIBC_2.27 nanf64 F -+GLIBC_2.27 nanf64x F -+GLIBC_2.27 nanl F -+GLIBC_2.27 nearbyint F -+GLIBC_2.27 nearbyintf F -+GLIBC_2.27 nearbyintf128 F -+GLIBC_2.27 nearbyintf32 F -+GLIBC_2.27 nearbyintf32x F -+GLIBC_2.27 nearbyintf64 F -+GLIBC_2.27 nearbyintf64x F -+GLIBC_2.27 nearbyintl F -+GLIBC_2.27 nextafter F -+GLIBC_2.27 nextafterf F -+GLIBC_2.27 nextafterf128 F -+GLIBC_2.27 nextafterf32 F -+GLIBC_2.27 nextafterf32x F -+GLIBC_2.27 nextafterf64 F -+GLIBC_2.27 nextafterf64x F -+GLIBC_2.27 nextafterl F -+GLIBC_2.27 nextdown F -+GLIBC_2.27 nextdownf F -+GLIBC_2.27 nextdownf128 F -+GLIBC_2.27 nextdownf32 F -+GLIBC_2.27 nextdownf32x F -+GLIBC_2.27 nextdownf64 F -+GLIBC_2.27 nextdownf64x F -+GLIBC_2.27 nextdownl F -+GLIBC_2.27 nexttoward F -+GLIBC_2.27 nexttowardf F -+GLIBC_2.27 nexttowardl F -+GLIBC_2.27 nextup F -+GLIBC_2.27 nextupf F -+GLIBC_2.27 nextupf128 F -+GLIBC_2.27 nextupf32 F -+GLIBC_2.27 nextupf32x F -+GLIBC_2.27 nextupf64 F -+GLIBC_2.27 nextupf64x F -+GLIBC_2.27 nextupl F -+GLIBC_2.27 pow F -+GLIBC_2.27 powf F -+GLIBC_2.27 powf128 F -+GLIBC_2.27 powf32 F -+GLIBC_2.27 powf32x F -+GLIBC_2.27 powf64 F -+GLIBC_2.27 powf64x F -+GLIBC_2.27 powl F -+GLIBC_2.27 remainder F -+GLIBC_2.27 remainderf F -+GLIBC_2.27 remainderf128 F -+GLIBC_2.27 remainderf32 F -+GLIBC_2.27 remainderf32x F -+GLIBC_2.27 remainderf64 F -+GLIBC_2.27 remainderf64x F -+GLIBC_2.27 remainderl F -+GLIBC_2.27 remquo F -+GLIBC_2.27 remquof F -+GLIBC_2.27 remquof128 F -+GLIBC_2.27 remquof32 F -+GLIBC_2.27 remquof32x F -+GLIBC_2.27 remquof64 F -+GLIBC_2.27 remquof64x F -+GLIBC_2.27 remquol F -+GLIBC_2.27 rint F -+GLIBC_2.27 rintf F -+GLIBC_2.27 rintf128 F -+GLIBC_2.27 rintf32 F -+GLIBC_2.27 rintf32x F -+GLIBC_2.27 rintf64 F -+GLIBC_2.27 rintf64x F -+GLIBC_2.27 rintl F -+GLIBC_2.27 round F -+GLIBC_2.27 roundeven F -+GLIBC_2.27 roundevenf F -+GLIBC_2.27 roundevenf128 F -+GLIBC_2.27 roundevenf32 F -+GLIBC_2.27 roundevenf32x F -+GLIBC_2.27 roundevenf64 F -+GLIBC_2.27 roundevenf64x F -+GLIBC_2.27 roundevenl F -+GLIBC_2.27 roundf F -+GLIBC_2.27 roundf128 F -+GLIBC_2.27 roundf32 F -+GLIBC_2.27 roundf32x F -+GLIBC_2.27 roundf64 F -+GLIBC_2.27 roundf64x F -+GLIBC_2.27 roundl F -+GLIBC_2.27 scalb F -+GLIBC_2.27 scalbf F -+GLIBC_2.27 scalbl F -+GLIBC_2.27 scalbln F -+GLIBC_2.27 scalblnf F -+GLIBC_2.27 scalblnf128 F -+GLIBC_2.27 scalblnf32 F -+GLIBC_2.27 scalblnf32x F -+GLIBC_2.27 scalblnf64 F -+GLIBC_2.27 scalblnf64x F -+GLIBC_2.27 scalblnl F -+GLIBC_2.27 scalbn F -+GLIBC_2.27 scalbnf F -+GLIBC_2.27 scalbnf128 F -+GLIBC_2.27 scalbnf32 F -+GLIBC_2.27 scalbnf32x F -+GLIBC_2.27 scalbnf64 F -+GLIBC_2.27 scalbnf64x F -+GLIBC_2.27 scalbnl F -+GLIBC_2.27 setpayload F -+GLIBC_2.27 setpayloadf F -+GLIBC_2.27 setpayloadf128 F -+GLIBC_2.27 setpayloadf32 F -+GLIBC_2.27 setpayloadf32x F -+GLIBC_2.27 setpayloadf64 F -+GLIBC_2.27 setpayloadf64x F -+GLIBC_2.27 setpayloadl F -+GLIBC_2.27 setpayloadsig F -+GLIBC_2.27 setpayloadsigf F -+GLIBC_2.27 setpayloadsigf128 F -+GLIBC_2.27 setpayloadsigf32 F -+GLIBC_2.27 setpayloadsigf32x F -+GLIBC_2.27 setpayloadsigf64 F -+GLIBC_2.27 setpayloadsigf64x F -+GLIBC_2.27 setpayloadsigl F -+GLIBC_2.27 signgam D 0x4 -+GLIBC_2.27 significand F -+GLIBC_2.27 significandf F -+GLIBC_2.27 significandl F -+GLIBC_2.27 sin F -+GLIBC_2.27 sincos F -+GLIBC_2.27 sincosf F -+GLIBC_2.27 sincosf128 F -+GLIBC_2.27 sincosf32 F -+GLIBC_2.27 sincosf32x F -+GLIBC_2.27 sincosf64 F -+GLIBC_2.27 sincosf64x F -+GLIBC_2.27 sincosl F -+GLIBC_2.27 sinf F -+GLIBC_2.27 sinf128 F -+GLIBC_2.27 sinf32 F -+GLIBC_2.27 sinf32x F -+GLIBC_2.27 sinf64 F -+GLIBC_2.27 sinf64x F -+GLIBC_2.27 sinh F -+GLIBC_2.27 sinhf F -+GLIBC_2.27 sinhf128 F -+GLIBC_2.27 sinhf32 F -+GLIBC_2.27 sinhf32x F -+GLIBC_2.27 sinhf64 F -+GLIBC_2.27 sinhf64x F -+GLIBC_2.27 sinhl F -+GLIBC_2.27 sinl F -+GLIBC_2.27 sqrt F -+GLIBC_2.27 sqrtf F -+GLIBC_2.27 sqrtf128 F -+GLIBC_2.27 sqrtf32 F -+GLIBC_2.27 sqrtf32x F -+GLIBC_2.27 sqrtf64 F -+GLIBC_2.27 sqrtf64x F -+GLIBC_2.27 sqrtl F -+GLIBC_2.27 tan F -+GLIBC_2.27 tanf F -+GLIBC_2.27 tanf128 F -+GLIBC_2.27 tanf32 F -+GLIBC_2.27 tanf32x F -+GLIBC_2.27 tanf64 F -+GLIBC_2.27 tanf64x F -+GLIBC_2.27 tanh F -+GLIBC_2.27 tanhf F -+GLIBC_2.27 tanhf128 F -+GLIBC_2.27 tanhf32 F -+GLIBC_2.27 tanhf32x F -+GLIBC_2.27 tanhf64 F -+GLIBC_2.27 tanhf64x F -+GLIBC_2.27 tanhl F -+GLIBC_2.27 tanl F -+GLIBC_2.27 tgamma F -+GLIBC_2.27 tgammaf F -+GLIBC_2.27 tgammaf128 F -+GLIBC_2.27 tgammaf32 F -+GLIBC_2.27 tgammaf32x F -+GLIBC_2.27 tgammaf64 F -+GLIBC_2.27 tgammaf64x F -+GLIBC_2.27 tgammal F -+GLIBC_2.27 totalorder F -+GLIBC_2.27 totalorderf F -+GLIBC_2.27 totalorderf128 F -+GLIBC_2.27 totalorderf32 F -+GLIBC_2.27 totalorderf32x F -+GLIBC_2.27 totalorderf64 F -+GLIBC_2.27 totalorderf64x F -+GLIBC_2.27 totalorderl F -+GLIBC_2.27 totalordermag F -+GLIBC_2.27 totalordermagf F -+GLIBC_2.27 totalordermagf128 F -+GLIBC_2.27 totalordermagf32 F -+GLIBC_2.27 totalordermagf32x F -+GLIBC_2.27 totalordermagf64 F -+GLIBC_2.27 totalordermagf64x F -+GLIBC_2.27 totalordermagl F -+GLIBC_2.27 trunc F -+GLIBC_2.27 truncf F -+GLIBC_2.27 truncf128 F -+GLIBC_2.27 truncf32 F -+GLIBC_2.27 truncf32x F -+GLIBC_2.27 truncf64 F -+GLIBC_2.27 truncf64x F -+GLIBC_2.27 truncl F -+GLIBC_2.27 ufromfp F -+GLIBC_2.27 ufromfpf F -+GLIBC_2.27 ufromfpf128 F -+GLIBC_2.27 ufromfpf32 F -+GLIBC_2.27 ufromfpf32x F -+GLIBC_2.27 ufromfpf64 F -+GLIBC_2.27 ufromfpf64x F -+GLIBC_2.27 ufromfpl F -+GLIBC_2.27 ufromfpx F -+GLIBC_2.27 ufromfpxf F -+GLIBC_2.27 ufromfpxf128 F -+GLIBC_2.27 ufromfpxf32 F -+GLIBC_2.27 ufromfpxf32x F -+GLIBC_2.27 ufromfpxf64 F -+GLIBC_2.27 ufromfpxf64x F -+GLIBC_2.27 ufromfpxl F -+GLIBC_2.27 y0 F -+GLIBC_2.27 y0f F -+GLIBC_2.27 y0f128 F -+GLIBC_2.27 y0f32 F -+GLIBC_2.27 y0f32x F -+GLIBC_2.27 y0f64 F -+GLIBC_2.27 y0f64x F -+GLIBC_2.27 y0l F -+GLIBC_2.27 y1 F -+GLIBC_2.27 y1f F -+GLIBC_2.27 y1f128 F -+GLIBC_2.27 y1f32 F -+GLIBC_2.27 y1f32x F -+GLIBC_2.27 y1f64 F -+GLIBC_2.27 y1f64x F -+GLIBC_2.27 y1l F -+GLIBC_2.27 yn F -+GLIBC_2.27 ynf F -+GLIBC_2.27 ynf128 F -+GLIBC_2.27 ynf32 F -+GLIBC_2.27 ynf32x F -+GLIBC_2.27 ynf64 F -+GLIBC_2.27 ynf64x F -+GLIBC_2.27 ynl F -+GLIBC_2.28 daddl F -+GLIBC_2.28 ddivl F -+GLIBC_2.28 dmull F -+GLIBC_2.28 dsubl F -+GLIBC_2.28 f32addf128 F -+GLIBC_2.28 f32addf32x F -+GLIBC_2.28 f32addf64 F -+GLIBC_2.28 f32addf64x F -+GLIBC_2.28 f32divf128 F -+GLIBC_2.28 f32divf32x F -+GLIBC_2.28 f32divf64 F -+GLIBC_2.28 f32divf64x F -+GLIBC_2.28 f32mulf128 F -+GLIBC_2.28 f32mulf32x F -+GLIBC_2.28 f32mulf64 F -+GLIBC_2.28 f32mulf64x F -+GLIBC_2.28 f32subf128 F -+GLIBC_2.28 f32subf32x F -+GLIBC_2.28 f32subf64 F -+GLIBC_2.28 f32subf64x F -+GLIBC_2.28 f32xaddf128 F -+GLIBC_2.28 f32xaddf64 F -+GLIBC_2.28 f32xaddf64x F -+GLIBC_2.28 f32xdivf128 F -+GLIBC_2.28 f32xdivf64 F -+GLIBC_2.28 f32xdivf64x F -+GLIBC_2.28 f32xmulf128 F -+GLIBC_2.28 f32xmulf64 F -+GLIBC_2.28 f32xmulf64x F -+GLIBC_2.28 f32xsubf128 F -+GLIBC_2.28 f32xsubf64 F -+GLIBC_2.28 f32xsubf64x F -+GLIBC_2.28 f64addf128 F -+GLIBC_2.28 f64addf64x F -+GLIBC_2.28 f64divf128 F -+GLIBC_2.28 f64divf64x F -+GLIBC_2.28 f64mulf128 F -+GLIBC_2.28 f64mulf64x F -+GLIBC_2.28 f64subf128 F -+GLIBC_2.28 f64subf64x F -+GLIBC_2.28 f64xaddf128 F -+GLIBC_2.28 f64xdivf128 F -+GLIBC_2.28 f64xmulf128 F -+GLIBC_2.28 f64xsubf128 F -+GLIBC_2.28 fadd F -+GLIBC_2.28 faddl F -+GLIBC_2.28 fdiv F -+GLIBC_2.28 fdivl F -+GLIBC_2.28 fmul F -+GLIBC_2.28 fmull F -+GLIBC_2.28 fsub F -+GLIBC_2.28 fsubl F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libnsl.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libnsl.abilist -new file mode 100644 -index 00000000..0767472d ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libnsl.abilist -@@ -0,0 +1,120 @@ -+GLIBC_2.27 __free_fdresult F -+GLIBC_2.27 __nis_default_access F -+GLIBC_2.27 __nis_default_group F -+GLIBC_2.27 __nis_default_owner F -+GLIBC_2.27 __nis_default_ttl F -+GLIBC_2.27 __nis_finddirectory F -+GLIBC_2.27 __nisbind_connect F -+GLIBC_2.27 __nisbind_create F -+GLIBC_2.27 __nisbind_destroy F -+GLIBC_2.27 __nisbind_next F -+GLIBC_2.27 __yp_check F -+GLIBC_2.27 nis_add F -+GLIBC_2.27 nis_add_entry F -+GLIBC_2.27 nis_addmember F -+GLIBC_2.27 nis_checkpoint F -+GLIBC_2.27 nis_clone_directory F -+GLIBC_2.27 nis_clone_object F -+GLIBC_2.27 nis_clone_result F -+GLIBC_2.27 nis_creategroup F -+GLIBC_2.27 nis_destroy_object F -+GLIBC_2.27 nis_destroygroup F -+GLIBC_2.27 nis_dir_cmp F -+GLIBC_2.27 nis_domain_of F -+GLIBC_2.27 nis_domain_of_r F -+GLIBC_2.27 nis_first_entry F -+GLIBC_2.27 nis_free_directory F -+GLIBC_2.27 nis_free_object F -+GLIBC_2.27 nis_free_request F -+GLIBC_2.27 nis_freenames F -+GLIBC_2.27 nis_freeresult F -+GLIBC_2.27 nis_freeservlist F -+GLIBC_2.27 nis_freetags F -+GLIBC_2.27 nis_getnames F -+GLIBC_2.27 nis_getservlist F -+GLIBC_2.27 nis_ismember F -+GLIBC_2.27 nis_leaf_of F -+GLIBC_2.27 nis_leaf_of_r F -+GLIBC_2.27 nis_lerror F -+GLIBC_2.27 nis_list F -+GLIBC_2.27 nis_local_directory F -+GLIBC_2.27 nis_local_group F -+GLIBC_2.27 nis_local_host F -+GLIBC_2.27 nis_local_principal F -+GLIBC_2.27 nis_lookup F -+GLIBC_2.27 nis_mkdir F -+GLIBC_2.27 nis_modify F -+GLIBC_2.27 nis_modify_entry F -+GLIBC_2.27 nis_name_of F -+GLIBC_2.27 nis_name_of_r F -+GLIBC_2.27 nis_next_entry F -+GLIBC_2.27 nis_perror F -+GLIBC_2.27 nis_ping F -+GLIBC_2.27 nis_print_directory F -+GLIBC_2.27 nis_print_entry F -+GLIBC_2.27 nis_print_group F -+GLIBC_2.27 nis_print_group_entry F -+GLIBC_2.27 nis_print_link F -+GLIBC_2.27 nis_print_object F -+GLIBC_2.27 nis_print_result F -+GLIBC_2.27 nis_print_rights F -+GLIBC_2.27 nis_print_table F -+GLIBC_2.27 nis_read_obj F -+GLIBC_2.27 nis_remove F -+GLIBC_2.27 nis_remove_entry F -+GLIBC_2.27 nis_removemember F -+GLIBC_2.27 nis_rmdir F -+GLIBC_2.27 nis_servstate F -+GLIBC_2.27 nis_sperrno F -+GLIBC_2.27 nis_sperror F -+GLIBC_2.27 nis_sperror_r F -+GLIBC_2.27 nis_stats F -+GLIBC_2.27 nis_verifygroup F -+GLIBC_2.27 nis_write_obj F -+GLIBC_2.27 readColdStartFile F -+GLIBC_2.27 writeColdStartFile F -+GLIBC_2.27 xdr_cback_data F -+GLIBC_2.27 xdr_domainname F -+GLIBC_2.27 xdr_keydat F -+GLIBC_2.27 xdr_mapname F -+GLIBC_2.27 xdr_obj_p F -+GLIBC_2.27 xdr_peername F -+GLIBC_2.27 xdr_valdat F -+GLIBC_2.27 xdr_yp_buf F -+GLIBC_2.27 xdr_ypall F -+GLIBC_2.27 xdr_ypbind_binding F -+GLIBC_2.27 xdr_ypbind_resp F -+GLIBC_2.27 xdr_ypbind_resptype F -+GLIBC_2.27 xdr_ypbind_setdom F -+GLIBC_2.27 xdr_ypdelete_args F -+GLIBC_2.27 xdr_ypmap_parms F -+GLIBC_2.27 xdr_ypmaplist F -+GLIBC_2.27 xdr_yppush_status F -+GLIBC_2.27 xdr_yppushresp_xfr F -+GLIBC_2.27 xdr_ypreq_key F -+GLIBC_2.27 xdr_ypreq_nokey F -+GLIBC_2.27 xdr_ypreq_xfr F -+GLIBC_2.27 xdr_ypresp_all F -+GLIBC_2.27 xdr_ypresp_key_val F -+GLIBC_2.27 xdr_ypresp_maplist F -+GLIBC_2.27 xdr_ypresp_master F -+GLIBC_2.27 xdr_ypresp_order F -+GLIBC_2.27 xdr_ypresp_val F -+GLIBC_2.27 xdr_ypresp_xfr F -+GLIBC_2.27 xdr_ypstat F -+GLIBC_2.27 xdr_ypupdate_args F -+GLIBC_2.27 xdr_ypxfrstat F -+GLIBC_2.27 yp_all F -+GLIBC_2.27 yp_bind F -+GLIBC_2.27 yp_first F -+GLIBC_2.27 yp_get_default_domain F -+GLIBC_2.27 yp_maplist F -+GLIBC_2.27 yp_master F -+GLIBC_2.27 yp_match F -+GLIBC_2.27 yp_next F -+GLIBC_2.27 yp_order F -+GLIBC_2.27 yp_unbind F -+GLIBC_2.27 yp_update F -+GLIBC_2.27 ypbinderr_string F -+GLIBC_2.27 yperr_string F -+GLIBC_2.27 ypprot_err F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libpthread.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libpthread.abilist -new file mode 100644 -index 00000000..f60b22ef ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libpthread.abilist -@@ -0,0 +1,264 @@ -+GLIBC_2.0 _IO_flockfile F -+GLIBC_2.0 _IO_ftrylockfile F -+GLIBC_2.0 _IO_funlockfile F -+GLIBC_2.0 __close F -+GLIBC_2.0 __connect F -+GLIBC_2.0 __errno_location F -+GLIBC_2.0 __fcntl F -+GLIBC_2.0 __fork F -+GLIBC_2.0 __h_errno_location F -+GLIBC_2.0 __lseek F -+GLIBC_2.0 __open F -+GLIBC_2.0 __pthread_getspecific F -+GLIBC_2.0 __pthread_key_create F -+GLIBC_2.0 __pthread_mutex_destroy F -+GLIBC_2.0 __pthread_mutex_init F -+GLIBC_2.0 __pthread_mutex_lock F -+GLIBC_2.0 __pthread_mutex_trylock F -+GLIBC_2.0 __pthread_mutex_unlock F -+GLIBC_2.0 __pthread_mutexattr_destroy F -+GLIBC_2.0 __pthread_mutexattr_init F -+GLIBC_2.0 __pthread_mutexattr_settype F -+GLIBC_2.0 __pthread_once F -+GLIBC_2.0 __pthread_setspecific F -+GLIBC_2.0 __read F -+GLIBC_2.0 __send F -+GLIBC_2.0 __sigaction F -+GLIBC_2.0 __wait F -+GLIBC_2.0 __write F -+GLIBC_2.0 _pthread_cleanup_pop F -+GLIBC_2.0 _pthread_cleanup_pop_restore F -+GLIBC_2.0 _pthread_cleanup_push F -+GLIBC_2.0 _pthread_cleanup_push_defer F -+GLIBC_2.0 accept F -+GLIBC_2.0 close F -+GLIBC_2.0 connect F -+GLIBC_2.0 fcntl F -+GLIBC_2.0 flockfile F -+GLIBC_2.0 fork F -+GLIBC_2.0 fsync F -+GLIBC_2.0 ftrylockfile F -+GLIBC_2.0 funlockfile F -+GLIBC_2.0 longjmp F -+GLIBC_2.0 lseek F -+GLIBC_2.0 msync F -+GLIBC_2.0 nanosleep F -+GLIBC_2.0 open F -+GLIBC_2.0 pause F -+GLIBC_2.0 pthread_atfork F -+GLIBC_2.0 pthread_attr_destroy F -+GLIBC_2.0 pthread_attr_getdetachstate F -+GLIBC_2.0 pthread_attr_getinheritsched F -+GLIBC_2.0 pthread_attr_getschedparam F -+GLIBC_2.0 pthread_attr_getschedpolicy F -+GLIBC_2.0 pthread_attr_getscope F -+GLIBC_2.0 pthread_attr_init F -+GLIBC_2.0 pthread_attr_setdetachstate F -+GLIBC_2.0 pthread_attr_setinheritsched F -+GLIBC_2.0 pthread_attr_setschedparam F -+GLIBC_2.0 pthread_attr_setschedpolicy F -+GLIBC_2.0 pthread_attr_setscope F -+GLIBC_2.0 pthread_cancel F -+GLIBC_2.0 pthread_cond_broadcast F -+GLIBC_2.0 pthread_cond_destroy F -+GLIBC_2.0 pthread_cond_init F -+GLIBC_2.0 pthread_cond_signal F -+GLIBC_2.0 pthread_cond_timedwait F -+GLIBC_2.0 pthread_cond_wait F -+GLIBC_2.0 pthread_condattr_destroy F -+GLIBC_2.0 pthread_condattr_init F -+GLIBC_2.0 pthread_create F -+GLIBC_2.0 pthread_detach F -+GLIBC_2.0 pthread_equal F -+GLIBC_2.0 pthread_exit F -+GLIBC_2.0 pthread_getschedparam F -+GLIBC_2.0 pthread_getspecific F -+GLIBC_2.0 pthread_join F -+GLIBC_2.0 pthread_key_create F -+GLIBC_2.0 pthread_key_delete F -+GLIBC_2.0 pthread_kill F -+GLIBC_2.0 pthread_kill_other_threads_np F -+GLIBC_2.0 pthread_mutex_destroy F -+GLIBC_2.0 pthread_mutex_init F -+GLIBC_2.0 pthread_mutex_lock F -+GLIBC_2.0 pthread_mutex_trylock F -+GLIBC_2.0 pthread_mutex_unlock F -+GLIBC_2.0 pthread_mutexattr_destroy F -+GLIBC_2.0 pthread_mutexattr_getkind_np F -+GLIBC_2.0 pthread_mutexattr_init F -+GLIBC_2.0 pthread_mutexattr_setkind_np F -+GLIBC_2.0 pthread_once F -+GLIBC_2.0 pthread_self F -+GLIBC_2.0 pthread_setcancelstate F -+GLIBC_2.0 pthread_setcanceltype F -+GLIBC_2.0 pthread_setschedparam F -+GLIBC_2.0 pthread_setspecific F -+GLIBC_2.0 pthread_sigmask F -+GLIBC_2.0 pthread_testcancel F -+GLIBC_2.0 raise F -+GLIBC_2.0 read F -+GLIBC_2.0 recv F -+GLIBC_2.0 recvfrom F -+GLIBC_2.0 recvmsg F -+GLIBC_2.0 sem_destroy F -+GLIBC_2.0 sem_getvalue F -+GLIBC_2.0 sem_init F -+GLIBC_2.0 sem_post F -+GLIBC_2.0 sem_trywait F -+GLIBC_2.0 sem_wait F -+GLIBC_2.0 send F -+GLIBC_2.0 sendmsg F -+GLIBC_2.0 sendto F -+GLIBC_2.0 sigaction F -+GLIBC_2.0 siglongjmp F -+GLIBC_2.0 sigwait F -+GLIBC_2.0 system F -+GLIBC_2.0 tcdrain F -+GLIBC_2.0 wait F -+GLIBC_2.0 waitpid F -+GLIBC_2.0 write F -+GLIBC_2.11 pthread_sigqueue F -+GLIBC_2.12 pthread_getname_np F -+GLIBC_2.12 pthread_mutex_consistent F -+GLIBC_2.12 pthread_mutexattr_getrobust F -+GLIBC_2.12 pthread_mutexattr_setrobust F -+GLIBC_2.12 pthread_setname_np F -+GLIBC_2.18 pthread_getattr_default_np F -+GLIBC_2.18 pthread_setattr_default_np F -+GLIBC_2.2 __libc_allocate_rtsig F -+GLIBC_2.2 __libc_current_sigrtmax F -+GLIBC_2.2 __libc_current_sigrtmin F -+GLIBC_2.2 __open64 F -+GLIBC_2.2 __pread64 F -+GLIBC_2.2 __pthread_rwlock_destroy F -+GLIBC_2.2 __pthread_rwlock_init F -+GLIBC_2.2 __pthread_rwlock_rdlock F -+GLIBC_2.2 __pthread_rwlock_tryrdlock F -+GLIBC_2.2 __pthread_rwlock_trywrlock F -+GLIBC_2.2 __pthread_rwlock_unlock F -+GLIBC_2.2 __pthread_rwlock_wrlock F -+GLIBC_2.2 __pwrite64 F -+GLIBC_2.2 __res_state F -+GLIBC_2.2 lseek64 F -+GLIBC_2.2 open64 F -+GLIBC_2.2 pread F -+GLIBC_2.2 pread64 F -+GLIBC_2.2 pthread_attr_getguardsize F -+GLIBC_2.2 pthread_attr_getstack F -+GLIBC_2.2 pthread_attr_getstackaddr F -+GLIBC_2.2 pthread_attr_getstacksize F -+GLIBC_2.2 pthread_attr_init F -+GLIBC_2.2 pthread_attr_setguardsize F -+GLIBC_2.2 pthread_attr_setstack F -+GLIBC_2.2 pthread_attr_setstackaddr F -+GLIBC_2.2 pthread_attr_setstacksize F -+GLIBC_2.2 pthread_barrier_destroy F -+GLIBC_2.2 pthread_barrier_init F -+GLIBC_2.2 pthread_barrier_wait F -+GLIBC_2.2 pthread_barrierattr_destroy F -+GLIBC_2.2 pthread_barrierattr_init F -+GLIBC_2.2 pthread_barrierattr_setpshared F -+GLIBC_2.2 pthread_condattr_getpshared F -+GLIBC_2.2 pthread_condattr_setpshared F -+GLIBC_2.2 pthread_create F -+GLIBC_2.2 pthread_getconcurrency F -+GLIBC_2.2 pthread_getcpuclockid F -+GLIBC_2.2 pthread_mutex_timedlock F -+GLIBC_2.2 pthread_mutexattr_getpshared F -+GLIBC_2.2 pthread_mutexattr_gettype F -+GLIBC_2.2 pthread_mutexattr_setpshared F -+GLIBC_2.2 pthread_mutexattr_settype F -+GLIBC_2.2 pthread_rwlock_destroy F -+GLIBC_2.2 pthread_rwlock_init F -+GLIBC_2.2 pthread_rwlock_rdlock F -+GLIBC_2.2 pthread_rwlock_timedrdlock F -+GLIBC_2.2 pthread_rwlock_timedwrlock F -+GLIBC_2.2 pthread_rwlock_tryrdlock F -+GLIBC_2.2 pthread_rwlock_trywrlock F -+GLIBC_2.2 pthread_rwlock_unlock F -+GLIBC_2.2 pthread_rwlock_wrlock F -+GLIBC_2.2 pthread_rwlockattr_destroy F -+GLIBC_2.2 pthread_rwlockattr_getkind_np F -+GLIBC_2.2 pthread_rwlockattr_getpshared F -+GLIBC_2.2 pthread_rwlockattr_init F -+GLIBC_2.2 pthread_rwlockattr_setkind_np F -+GLIBC_2.2 pthread_rwlockattr_setpshared F -+GLIBC_2.2 pthread_setconcurrency F -+GLIBC_2.2 pthread_spin_destroy F -+GLIBC_2.2 pthread_spin_init F -+GLIBC_2.2 pthread_spin_lock F -+GLIBC_2.2 pthread_spin_trylock F -+GLIBC_2.2 pthread_spin_unlock F -+GLIBC_2.2 pthread_yield F -+GLIBC_2.2 pwrite F -+GLIBC_2.2 pwrite64 F -+GLIBC_2.2 sem_close F -+GLIBC_2.2 sem_destroy F -+GLIBC_2.2 sem_getvalue F -+GLIBC_2.2 sem_init F -+GLIBC_2.2 sem_open F -+GLIBC_2.2 sem_post F -+GLIBC_2.2 sem_timedwait F -+GLIBC_2.2 sem_trywait F -+GLIBC_2.2 sem_unlink F -+GLIBC_2.2 sem_wait F -+GLIBC_2.2.3 pthread_getattr_np F -+GLIBC_2.2.6 __nanosleep F -+GLIBC_2.28 call_once F -+GLIBC_2.28 cnd_broadcast F -+GLIBC_2.28 cnd_destroy F -+GLIBC_2.28 cnd_init F -+GLIBC_2.28 cnd_signal F -+GLIBC_2.28 cnd_timedwait F -+GLIBC_2.28 cnd_wait F -+GLIBC_2.28 mtx_destroy F -+GLIBC_2.28 mtx_init F -+GLIBC_2.28 mtx_lock F -+GLIBC_2.28 mtx_timedlock F -+GLIBC_2.28 mtx_trylock F -+GLIBC_2.28 mtx_unlock F -+GLIBC_2.28 thrd_create F -+GLIBC_2.28 thrd_detach F -+GLIBC_2.28 thrd_exit F -+GLIBC_2.28 thrd_join F -+GLIBC_2.28 tss_create F -+GLIBC_2.28 tss_delete F -+GLIBC_2.28 tss_get F -+GLIBC_2.28 tss_set F -+GLIBC_2.3.2 pthread_cond_broadcast F -+GLIBC_2.3.2 pthread_cond_destroy F -+GLIBC_2.3.2 pthread_cond_init F -+GLIBC_2.3.2 pthread_cond_signal F -+GLIBC_2.3.2 pthread_cond_timedwait F -+GLIBC_2.3.2 pthread_cond_wait F -+GLIBC_2.3.3 __pthread_cleanup_routine F -+GLIBC_2.3.3 __pthread_register_cancel F -+GLIBC_2.3.3 __pthread_register_cancel_defer F -+GLIBC_2.3.3 __pthread_unregister_cancel F -+GLIBC_2.3.3 __pthread_unregister_cancel_restore F -+GLIBC_2.3.3 __pthread_unwind_next F -+GLIBC_2.3.3 pthread_attr_getaffinity_np F -+GLIBC_2.3.3 pthread_attr_setaffinity_np F -+GLIBC_2.3.3 pthread_attr_setstack F -+GLIBC_2.3.3 pthread_attr_setstacksize F -+GLIBC_2.3.3 pthread_barrierattr_getpshared F -+GLIBC_2.3.3 pthread_condattr_getclock F -+GLIBC_2.3.3 pthread_condattr_setclock F -+GLIBC_2.3.3 pthread_getaffinity_np F -+GLIBC_2.3.3 pthread_setaffinity_np F -+GLIBC_2.3.3 pthread_timedjoin_np F -+GLIBC_2.3.3 pthread_tryjoin_np F -+GLIBC_2.3.4 pthread_attr_getaffinity_np F -+GLIBC_2.3.4 pthread_attr_setaffinity_np F -+GLIBC_2.3.4 pthread_getaffinity_np F -+GLIBC_2.3.4 pthread_setaffinity_np F -+GLIBC_2.3.4 pthread_setschedprio F -+GLIBC_2.4 pthread_mutex_consistent_np F -+GLIBC_2.4 pthread_mutex_getprioceiling F -+GLIBC_2.4 pthread_mutex_setprioceiling F -+GLIBC_2.4 pthread_mutexattr_getprioceiling F -+GLIBC_2.4 pthread_mutexattr_getprotocol F -+GLIBC_2.4 pthread_mutexattr_getrobust_np F -+GLIBC_2.4 pthread_mutexattr_setprioceiling F -+GLIBC_2.4 pthread_mutexattr_setprotocol F -+GLIBC_2.4 pthread_mutexattr_setrobust_np F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libresolv.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libresolv.abilist -new file mode 100644 -index 00000000..eb9c1cb7 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libresolv.abilist -@@ -0,0 +1,79 @@ -+GLIBC_2.27 __b64_ntop F -+GLIBC_2.27 __b64_pton F -+GLIBC_2.27 __dn_comp F -+GLIBC_2.27 __dn_count_labels F -+GLIBC_2.27 __dn_expand F -+GLIBC_2.27 __dn_skipname F -+GLIBC_2.27 __fp_nquery F -+GLIBC_2.27 __fp_query F -+GLIBC_2.27 __fp_resstat F -+GLIBC_2.27 __hostalias F -+GLIBC_2.27 __loc_aton F -+GLIBC_2.27 __loc_ntoa F -+GLIBC_2.27 __p_cdname F -+GLIBC_2.27 __p_cdnname F -+GLIBC_2.27 __p_class F -+GLIBC_2.27 __p_class_syms D 0xa8 -+GLIBC_2.27 __p_fqname F -+GLIBC_2.27 __p_fqnname F -+GLIBC_2.27 __p_option F -+GLIBC_2.27 __p_query F -+GLIBC_2.27 __p_rcode F -+GLIBC_2.27 __p_time F -+GLIBC_2.27 __p_type F -+GLIBC_2.27 __p_type_syms D 0x450 -+GLIBC_2.27 __putlong F -+GLIBC_2.27 __putshort F -+GLIBC_2.27 __res_close F -+GLIBC_2.27 __res_dnok F -+GLIBC_2.27 __res_hnok F -+GLIBC_2.27 __res_hostalias F -+GLIBC_2.27 __res_isourserver F -+GLIBC_2.27 __res_mailok F -+GLIBC_2.27 __res_mkquery F -+GLIBC_2.27 __res_nameinquery F -+GLIBC_2.27 __res_nmkquery F -+GLIBC_2.27 __res_nquery F -+GLIBC_2.27 __res_nquerydomain F -+GLIBC_2.27 __res_nsearch F -+GLIBC_2.27 __res_nsend F -+GLIBC_2.27 __res_ownok F -+GLIBC_2.27 __res_queriesmatch F -+GLIBC_2.27 __res_query F -+GLIBC_2.27 __res_querydomain F -+GLIBC_2.27 __res_search F -+GLIBC_2.27 __res_send F -+GLIBC_2.27 __sym_ntop F -+GLIBC_2.27 __sym_ntos F -+GLIBC_2.27 __sym_ston F -+GLIBC_2.27 _getlong F -+GLIBC_2.27 _getshort F -+GLIBC_2.27 inet_net_ntop F -+GLIBC_2.27 inet_net_pton F -+GLIBC_2.27 inet_neta F -+GLIBC_2.27 ns_datetosecs F -+GLIBC_2.27 ns_format_ttl F -+GLIBC_2.27 ns_get16 F -+GLIBC_2.27 ns_get32 F -+GLIBC_2.27 ns_initparse F -+GLIBC_2.27 ns_makecanon F -+GLIBC_2.27 ns_msg_getflag F -+GLIBC_2.27 ns_name_compress F -+GLIBC_2.27 ns_name_ntol F -+GLIBC_2.27 ns_name_ntop F -+GLIBC_2.27 ns_name_pack F -+GLIBC_2.27 ns_name_pton F -+GLIBC_2.27 ns_name_rollback F -+GLIBC_2.27 ns_name_skip F -+GLIBC_2.27 ns_name_uncompress F -+GLIBC_2.27 ns_name_unpack F -+GLIBC_2.27 ns_parse_ttl F -+GLIBC_2.27 ns_parserr F -+GLIBC_2.27 ns_put16 F -+GLIBC_2.27 ns_put32 F -+GLIBC_2.27 ns_samedomain F -+GLIBC_2.27 ns_samename F -+GLIBC_2.27 ns_skiprr F -+GLIBC_2.27 ns_sprintrr F -+GLIBC_2.27 ns_sprintrrf F -+GLIBC_2.27 ns_subdomain F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/librt.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/librt.abilist -new file mode 100644 -index 00000000..bfd262ec ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/librt.abilist -@@ -0,0 +1,35 @@ -+GLIBC_2.27 __mq_open_2 F -+GLIBC_2.27 aio_cancel F -+GLIBC_2.27 aio_cancel64 F -+GLIBC_2.27 aio_error F -+GLIBC_2.27 aio_error64 F -+GLIBC_2.27 aio_fsync F -+GLIBC_2.27 aio_fsync64 F -+GLIBC_2.27 aio_init F -+GLIBC_2.27 aio_read F -+GLIBC_2.27 aio_read64 F -+GLIBC_2.27 aio_return F -+GLIBC_2.27 aio_return64 F -+GLIBC_2.27 aio_suspend F -+GLIBC_2.27 aio_suspend64 F -+GLIBC_2.27 aio_write F -+GLIBC_2.27 aio_write64 F -+GLIBC_2.27 lio_listio F -+GLIBC_2.27 lio_listio64 F -+GLIBC_2.27 mq_close F -+GLIBC_2.27 mq_getattr F -+GLIBC_2.27 mq_notify F -+GLIBC_2.27 mq_open F -+GLIBC_2.27 mq_receive F -+GLIBC_2.27 mq_send F -+GLIBC_2.27 mq_setattr F -+GLIBC_2.27 mq_timedreceive F -+GLIBC_2.27 mq_timedsend F -+GLIBC_2.27 mq_unlink F -+GLIBC_2.27 shm_open F -+GLIBC_2.27 shm_unlink F -+GLIBC_2.27 timer_create F -+GLIBC_2.27 timer_delete F -+GLIBC_2.27 timer_getoverrun F -+GLIBC_2.27 timer_gettime F -+GLIBC_2.27 timer_settime F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libthread_db.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libthread_db.abilist -new file mode 100644 -index 00000000..4122e563 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libthread_db.abilist -@@ -0,0 +1,40 @@ -+GLIBC_2.27 td_init F -+GLIBC_2.27 td_log F -+GLIBC_2.27 td_symbol_list F -+GLIBC_2.27 td_ta_clear_event F -+GLIBC_2.27 td_ta_delete F -+GLIBC_2.27 td_ta_enable_stats F -+GLIBC_2.27 td_ta_event_addr F -+GLIBC_2.27 td_ta_event_getmsg F -+GLIBC_2.27 td_ta_get_nthreads F -+GLIBC_2.27 td_ta_get_ph F -+GLIBC_2.27 td_ta_get_stats F -+GLIBC_2.27 td_ta_map_id2thr F -+GLIBC_2.27 td_ta_map_lwp2thr F -+GLIBC_2.27 td_ta_new F -+GLIBC_2.27 td_ta_reset_stats F -+GLIBC_2.27 td_ta_set_event F -+GLIBC_2.27 td_ta_setconcurrency F -+GLIBC_2.27 td_ta_thr_iter F -+GLIBC_2.27 td_ta_tsd_iter F -+GLIBC_2.27 td_thr_clear_event F -+GLIBC_2.27 td_thr_dbresume F -+GLIBC_2.27 td_thr_dbsuspend F -+GLIBC_2.27 td_thr_event_enable F -+GLIBC_2.27 td_thr_event_getmsg F -+GLIBC_2.27 td_thr_get_info F -+GLIBC_2.27 td_thr_getfpregs F -+GLIBC_2.27 td_thr_getgregs F -+GLIBC_2.27 td_thr_getxregs F -+GLIBC_2.27 td_thr_getxregsize F -+GLIBC_2.27 td_thr_set_event F -+GLIBC_2.27 td_thr_setfpregs F -+GLIBC_2.27 td_thr_setgregs F -+GLIBC_2.27 td_thr_setprio F -+GLIBC_2.27 td_thr_setsigpending F -+GLIBC_2.27 td_thr_setxregs F -+GLIBC_2.27 td_thr_sigsetmask F -+GLIBC_2.27 td_thr_tls_get_addr F -+GLIBC_2.27 td_thr_tlsbase F -+GLIBC_2.27 td_thr_tsd F -+GLIBC_2.27 td_thr_validate F -diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libutil.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libutil.abilist -new file mode 100644 -index 00000000..cbfec8d4 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libutil.abilist -@@ -0,0 +1,6 @@ -+GLIBC_2.27 forkpty F -+GLIBC_2.27 login F -+GLIBC_2.27 login_tty F -+GLIBC_2.27 logout F -+GLIBC_2.27 logwtmp F -+GLIBC_2.27 openpty F -diff --git a/sysdeps/unix/sysv/linux/loongarch/makecontext.c b/sysdeps/unix/sysv/linux/loongarch/makecontext.c -new file mode 100644 -index 00000000..55d509ab ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/makecontext.c -@@ -0,0 +1,78 @@ -+/* Copyright (C) 2020-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 -+ -+void -+__makecontext (ucontext_t *ucp, void (*func) (void), int argc, -+ long int a0, long int a1, long int a2, long int a3, long int a4, -+ ...) -+{ -+ extern void __start_context (void) attribute_hidden; -+ long int i, sp; -+ -+ _Static_assert (LARCH_REG_NARGS == 8, "__makecontext assumes 8 argument registers"); -+ -+ /* Set up the stack. */ -+ sp = ((long int) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size) & ALMASK; -+ -+ /* Set up the register context. -+ ra = s0 = 0, terminating the stack for backtracing purposes. -+ s1 = the function we must call. -+ s2 = the subsequent context to run. */ -+ ucp->uc_mcontext.__gregs[LARCH_REG_RA] = 0; -+ ucp->uc_mcontext.__gregs[LARCH_REG_S0] = 0; -+ ucp->uc_mcontext.__gregs[LARCH_REG_S1] = (long int) func; -+ ucp->uc_mcontext.__gregs[LARCH_REG_S2] = (long int) ucp->uc_link; -+ ucp->uc_mcontext.__gregs[LARCH_REG_SP] = sp; -+ ucp->uc_mcontext.__pc = (long int) &__start_context; -+ -+ /* Put args in a0-a7, then put any remaining args on the stack. */ -+ ucp->uc_mcontext.__gregs[LARCH_REG_A0 + 0] = a0; -+ ucp->uc_mcontext.__gregs[LARCH_REG_A0 + 1] = a1; -+ ucp->uc_mcontext.__gregs[LARCH_REG_A0 + 2] = a2; -+ ucp->uc_mcontext.__gregs[LARCH_REG_A0 + 3] = a3; -+ ucp->uc_mcontext.__gregs[LARCH_REG_A0 + 4] = a4; -+ -+ if (__glibc_unlikely (argc > 5)) -+ { -+ va_list vl; -+ va_start (vl, a4); -+ -+ long reg_args = argc < LARCH_REG_NARGS ? argc : LARCH_REG_NARGS; -+ for (i = 5; i < reg_args; i++) -+ ucp->uc_mcontext.__gregs[LARCH_REG_A0 + i] = va_arg (vl, long); -+ -+ long int stack_args = argc - reg_args; -+ if (stack_args > 0) -+ { -+ sp = (sp - stack_args * sizeof (long int)) & ALMASK; -+ ucp->uc_mcontext.__gregs[LARCH_REG_SP] = sp; -+ for (i = 0; i < stack_args; i++) -+ ((long int *) sp)[i] = va_arg (vl, long int); -+ } -+ -+ va_end (vl); -+ } -+} -+ -+weak_alias (__makecontext, makecontext) -diff --git a/sysdeps/unix/sysv/linux/loongarch/profil-counter.h b/sysdeps/unix/sysv/linux/loongarch/profil-counter.h -new file mode 100644 -index 00000000..6a3cc201 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/profil-counter.h -@@ -0,0 +1,31 @@ -+/* Copyright (C) 2020-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 -+ -+static void -+__profil_counter (int signo, const SIGCONTEXT scp) -+{ -+ profil_count ((void *) GET_PC (scp)); -+ -+ /* This is a hack to prevent the compiler from implementing the -+ above function call as a sibcall. The sibcall would overwrite -+ the signal context. */ -+ asm volatile (""); -+} -diff --git a/sysdeps/unix/sysv/linux/loongarch/pt-vfork.S b/sysdeps/unix/sysv/linux/loongarch/pt-vfork.S -new file mode 100644 -index 00000000..1cc89317 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/pt-vfork.S -@@ -0,0 +1 @@ -+/* Not needed. */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/register-dump.h b/sysdeps/unix/sysv/linux/loongarch/register-dump.h -new file mode 100644 -index 00000000..5e45d5c7 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/register-dump.h -@@ -0,0 +1,63 @@ -+/* Dump registers. -+ Copyright (C) 2000-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#include -+#include -+#include <_itoa.h> -+ -+static void -+hexvalue (unsigned long int value, char *buf, size_t len) -+{ -+ char *cp = _itoa_word (value, buf + len, 16, 0); -+ while (cp > buf) -+ *--cp = '0'; -+} -+ -+#define REGDUMP_NREGS 32 -+#define REGDUMP_PER_LINE (80 / (__WORDSIZE / 4 + 4)) -+ -+static void -+register_dump (int fd, ucontext_t *ctx) -+{ -+ int i; -+ char regvalue[__WORDSIZE / 4 + 1]; -+ char str[82 * ((REGDUMP_NREGS + REGDUMP_PER_LINE - 1) / REGDUMP_PER_LINE)]; -+ -+ static const char names[REGDUMP_NREGS][4] = { -+ "pc", "ra", "tp", "sp", "a0", "a1", "a2", "a3", -+ "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", -+ "t4", "t5", "t6", "t7", "t8", "x" , "fp", "s0", -+ "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8" -+ }; -+ -+ str[0] = 0; -+ for (i = 0; i < REGDUMP_NREGS; i++) -+ { -+ strcat (str, names[i]); -+ strcat (str, " "); -+ hexvalue (ctx->uc_mcontext.__gregs[i], regvalue, __WORDSIZE / 4); -+ strcat (str, regvalue); -+ -+ if ((i + 1) % REGDUMP_PER_LINE == 0) -+ strcat (str, "\n"); -+ } -+ -+ write (fd, str, strlen (str)); -+} -+ -+#define REGISTER_DUMP register_dump (fd, ctx) -diff --git a/sysdeps/unix/sysv/linux/loongarch/setcontext.S b/sysdeps/unix/sysv/linux/loongarch/setcontext.S -new file mode 100644 -index 00000000..c96ec43c ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/setcontext.S -@@ -0,0 +1,111 @@ -+/* Set current context. -+ Copyright (C) 2009-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+#include "sys/regdef.h" -+#include "ucontext-macros.h" -+ -+/* int __setcontext (const ucontext_t *ucp) -+ -+ Restores the machine context in UCP and thereby resumes execution -+ in that context. -+ -+ This implementation is intended to be used for *synchronous* context -+ switches only. Therefore, it does not have to restore anything -+ other than the PRESERVED state. */ -+ -+ .text -+LEAF (__setcontext) -+ -+ addi.d sp, sp, -16 -+ st.d a0, sp, 0 /* Save ucp to stack. */ -+/* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, NULL, _NSIG8) */ -+ li.d a3, _NSIG8 -+ li.d a2, 0 -+ addi.d a1, a0, UCONTEXT_SIGMASK -+ li.d a0, SIG_SETMASK -+ -+ li.d a7, SYS_ify (rt_sigprocmask) -+ syscall 0 -+ -+ blt a0, $r0, 99f -+ -+ ld.d t0, sp, 0 /* Load ucp to t0. */ -+ cfi_def_cfa (12, 0) -+ -+#ifndef __loongarch_soft_float -+ ld.w t1, t0, MCONTEXT_FCSR -+ -+ RESTORE_FP_REG (fs0, 24, t0) -+ RESTORE_FP_REG (fs1, 25, t0) -+ RESTORE_FP_REG (fs2, 26, t0) -+ RESTORE_FP_REG (fs3, 27, t0) -+ RESTORE_FP_REG (fs4, 28, t0) -+ RESTORE_FP_REG (fs5, 29, t0) -+ RESTORE_FP_REG (fs6, 30, t0) -+ RESTORE_FP_REG (fs7, 31, t0) -+ -+ movgr2fcsr $r0, t1 -+#endif /* __loongarch_soft_float */ -+ -+ /* Note the contents of argument registers will be random -+ unless makecontext() has been called. */ -+ RESTORE_INT_REG (ra, 1, t0) -+ RESTORE_INT_REG (sp, 3, t0) -+ RESTORE_INT_REG (a0, 4, t0) -+ RESTORE_INT_REG (a1, 5, t0) -+ RESTORE_INT_REG (a2, 6, t0) -+ RESTORE_INT_REG (a3, 7, t0) -+ RESTORE_INT_REG (a4, 8, t0) -+ RESTORE_INT_REG (a5, 9, t0) -+ RESTORE_INT_REG (a6, 10, t0) -+ RESTORE_INT_REG (a7, 11, t0) -+ RESTORE_INT_REG (x, 21, t0) -+ RESTORE_INT_REG (fp, 22, t0) -+ RESTORE_INT_REG (s0, 23, t0) -+ RESTORE_INT_REG (s1, 24, t0) -+ RESTORE_INT_REG (s2, 25, t0) -+ RESTORE_INT_REG (s3, 26, t0) -+ RESTORE_INT_REG (s4, 27, t0) -+ RESTORE_INT_REG (s5, 28, t0) -+ RESTORE_INT_REG (s6, 29, t0) -+ RESTORE_INT_REG (s7, 30, t0) -+ RESTORE_INT_REG (s8, 31, t0) -+ ld.d t1, t0, MCONTEXT_PC -+ jirl $r0,t1,0 -+ -+99: -+ addi.d sp, sp, 16 -+ b __syscall_error -+ -+PSEUDO_END (__setcontext) -+weak_alias (__setcontext, setcontext) -+ -+LEAF (__start_context) -+ -+ /* Terminate call stack by noting ra == 0. Happily, s0 == 0 here. */ -+ cfi_register (1, 23) -+ -+ /* Call the function passed to makecontext. */ -+ jirl $r1,s1,0 -+ -+ /* Invoke subsequent context if present, else exit(0). */ -+ ori a0, s2, 0 -+ beqz s2, 1f -+ bl __setcontext -+1: b exit -+ -+PSEUDO_END (__start_context) -diff --git a/sysdeps/unix/sysv/linux/loongarch/shlib-versions b/sysdeps/unix/sysv/linux/loongarch/shlib-versions -new file mode 100644 -index 00000000..2a67fe71 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/shlib-versions -@@ -0,0 +1,2 @@ -+DEFAULT GLIBC_2.27 -+libpthread=0 GLIBC_2.0 GLIBC_2.2 -diff --git a/sysdeps/unix/sysv/linux/loongarch/sigcontextinfo.h b/sysdeps/unix/sysv/linux/loongarch/sigcontextinfo.h -new file mode 100644 -index 00000000..2a864795 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/sigcontextinfo.h -@@ -0,0 +1,22 @@ -+/* Copyright (C) 2020-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 -+ -+#define SIGCONTEXT siginfo_t *_si, ucontext_t * -+#define GET_PC(ctx) ((void *) ctx->uc_mcontext.__pc) -diff --git a/sysdeps/unix/sysv/linux/loongarch/swapcontext.S b/sysdeps/unix/sysv/linux/loongarch/swapcontext.S -new file mode 100644 -index 00000000..d839dd87 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/swapcontext.S -@@ -0,0 +1,120 @@ -+/* Save and set current context. -+ Copyright (C) 2009-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#include "ucontext-macros.h" -+ -+/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */ -+ -+LEAF (__swapcontext) -+ ori a2, sp, 0 /* Save sp to a2. */ -+ addi.d sp, sp, -16 -+ st.d a1, sp, 0 -+ ori t0, a1, 0 -+ -+ SAVE_INT_REG (ra, 1, a0) -+ SAVE_INT_REG (a2, 3, a0) /* Store sp .*/ -+ SAVE_INT_REG (zero, 4, a0) /* return 0 by overwriting a0. */ -+ SAVE_INT_REG (x, 21, a0) -+ SAVE_INT_REG (fp, 22, a0) -+ SAVE_INT_REG (s0, 23, a0) -+ SAVE_INT_REG (s1, 24, a0) -+ SAVE_INT_REG (s2, 25, a0) -+ SAVE_INT_REG (s3, 26, a0) -+ SAVE_INT_REG (s4, 27, a0) -+ SAVE_INT_REG (s5, 28, a0) -+ SAVE_INT_REG (s6, 29, a0) -+ SAVE_INT_REG (s7, 30, a0) -+ SAVE_INT_REG (s8, 31, a0) -+ st.d ra, a0, MCONTEXT_PC -+#ifndef __loongarch_soft_float -+ movfcsr2gr a1, $r0 -+ -+ SAVE_FP_REG (fs0, 24, a0) -+ SAVE_FP_REG (fs1, 25, a0) -+ SAVE_FP_REG (fs2, 26, a0) -+ SAVE_FP_REG (fs3, 27, a0) -+ SAVE_FP_REG (fs4, 28, a0) -+ SAVE_FP_REG (fs5, 29, a0) -+ SAVE_FP_REG (fs6, 30, a0) -+ SAVE_FP_REG (fs7, 31, a0) -+ -+ st.w a1, a0, MCONTEXT_FCSR -+#endif /* __loongarch_soft_float */ -+ -+/* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, _NSIG8) */ -+ li.d a3, _NSIG8 -+ addi.d a2, a0, UCONTEXT_SIGMASK -+ addi.d a1, t0, UCONTEXT_SIGMASK -+ li.d a0, SIG_SETMASK -+ -+ li.d a7, SYS_ify (rt_sigprocmask) -+ syscall 0 -+ -+ blt a0, zero, 99f -+ -+#ifndef __loongarch_soft_float -+ ld.d t0, sp, 0 /* Load a1 to t0. */ -+ ld.w t1, t0, MCONTEXT_FCSR -+ -+ RESTORE_FP_REG (fs0, 24, t0) -+ RESTORE_FP_REG (fs1, 25, t0) -+ RESTORE_FP_REG (fs2, 26, t0) -+ RESTORE_FP_REG (fs3, 27, t0) -+ RESTORE_FP_REG (fs4, 28, t0) -+ RESTORE_FP_REG (fs5, 29, t0) -+ RESTORE_FP_REG (fs6, 30, t0) -+ RESTORE_FP_REG (fs7, 31, t0) -+ -+ movgr2fcsr $r0, t1 -+#endif /* __loongarch_soft_float */ -+ -+ /* Note the contents of argument registers will be random -+ unless makecontext() has been called. */ -+ RESTORE_INT_REG (ra, 1, t0) -+ RESTORE_INT_REG (sp, 3, t0) -+ RESTORE_INT_REG (a0, 4, t0) -+ RESTORE_INT_REG (a1, 5, t0) -+ RESTORE_INT_REG (a2, 6, t0) -+ RESTORE_INT_REG (a3, 7, t0) -+ RESTORE_INT_REG (a4, 8, t0) -+ RESTORE_INT_REG (a5, 9, t0) -+ RESTORE_INT_REG (a6, 10, t0) -+ RESTORE_INT_REG (a7, 11, t0) -+ RESTORE_INT_REG (x, 21, t0) -+ RESTORE_INT_REG (fp, 22, t0) -+ RESTORE_INT_REG (s0, 23, t0) -+ RESTORE_INT_REG (s1, 24, t0) -+ RESTORE_INT_REG (s2, 25, t0) -+ RESTORE_INT_REG (s3, 26, t0) -+ RESTORE_INT_REG (s4, 27, t0) -+ RESTORE_INT_REG (s5, 28, t0) -+ RESTORE_INT_REG (s6, 29, t0) -+ RESTORE_INT_REG (s7, 30, t0) -+ RESTORE_INT_REG (s8, 31, t0) -+ ld.d t1, t0, MCONTEXT_PC -+ -+ jirl $r0, t1, 0 -+ -+ -+99: -+ addi.d sp, sp, 16 -+ b __syscall_error -+ -+PSEUDO_END (__swapcontext) -+ -+weak_alias (__swapcontext, swapcontext) -diff --git a/sysdeps/unix/sysv/linux/loongarch/sys/procfs.h b/sysdeps/unix/sysv/linux/loongarch/sys/procfs.h -new file mode 100644 -index 00000000..9ae06b40 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/sys/procfs.h -@@ -0,0 +1,122 @@ -+/* Copyright (C) 2020-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 _SYS_PROCFS_H -+#define _SYS_PROCFS_H 1 -+ -+/* This is somehow modelled after the file of the same name on SysVr4 -+ systems. It provides a definition of the core file format for ELF -+ used on Linux. */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+__BEGIN_DECLS -+ -+/* Type for a general-purpose register. */ -+typedef uint64_t elf_greg_t; -+ -+/* And the whole bunch of them. We could have used `struct -+ pt_regs' directly in the typedef, but tradition says that -+ the register set is an array, which does have some peculiar -+ semantics, so leave it that way. */ -+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) -+typedef elf_greg_t elf_gregset_t[ELF_NGREG]; -+ -+#define ELF_NFPREG 34 /* 32 FPRs + 8-byte byte-vec for fcc + 4-byte FCR */ -+typedef union { double d; float f; } elf_fpreg_t; -+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; -+ -+typedef union { double d[2]; float f[4]; } __attribute__((__aligned__ (16))) elf_lsxregset_t[32]; -+typedef union { double d[4]; float f[8]; } __attribute__((__aligned__ (32))) elf_lasxregset_t[32]; -+ -+struct elf_siginfo -+ { -+ int si_signo; /* Signal number. */ -+ int si_code; /* Extra code. */ -+ int si_errno; /* Errno. */ -+ }; -+ -+/* Definitions to generate Intel SVR4-like core files. These mostly -+ have the same names as the SVR4 types with "elf_" tacked on the -+ front to prevent clashes with linux definitions, and the typedef -+ forms have been avoided. This is mostly like the SVR4 structure, -+ but more Linuxy, with things that Linux does not support and which -+ gdb doesn't really use excluded. Fields present but not used are -+ marked with "XXX". */ -+struct elf_prstatus -+ { -+ struct elf_siginfo pr_info; /* Info associated with signal. */ -+ short int pr_cursig; /* Current signal. */ -+ unsigned long int pr_sigpend; /* Set of pending signals. */ -+ unsigned long int pr_sighold; /* Set of held signals. */ -+ __pid_t pr_pid; -+ __pid_t pr_ppid; -+ __pid_t pr_pgrp; -+ __pid_t pr_sid; -+ struct timeval pr_utime; /* User time. */ -+ struct timeval pr_stime; /* System time. */ -+ struct timeval pr_cutime; /* Cumulative user time. */ -+ struct timeval pr_cstime; /* Cumulative system time. */ -+ elf_gregset_t pr_reg; /* GP registers. */ -+ int pr_fpvalid; /* True if math copro being used. */ -+ }; -+ -+ -+#define ELF_PRARGSZ (80) /* Number of chars for args */ -+ -+struct elf_prpsinfo -+ { -+ char pr_state; /* Numeric process state. */ -+ char pr_sname; /* Char for pr_state. */ -+ char pr_zomb; /* Zombie. */ -+ char pr_nice; /* Nice val. */ -+ unsigned long int pr_flag; /* Flags. */ -+ unsigned int pr_uid; -+ unsigned int pr_gid; -+ int pr_pid, pr_ppid, pr_pgrp, pr_sid; -+ /* Lots missing */ -+ char pr_fname[16]; /* Filename of executable. */ -+ char pr_psargs[ELF_PRARGSZ]; /* Initial part of arg list. */ -+ }; -+ -+/* The rest of this file provides the types for emulation of the -+ Solaris interfaces that should be implemented by -+ users of libthread_db. */ -+ -+/* Addresses. */ -+typedef void *psaddr_t; -+ -+/* Register sets. Linux has different names. */ -+typedef elf_gregset_t prgregset_t; -+typedef elf_fpregset_t prfpregset_t; -+ -+/* We don't have any differences between processes and threads, -+ therefore habe only ine PID type. */ -+typedef __pid_t lwpid_t; -+ -+/* Process status and info. In the end we do provide typedefs for them. */ -+typedef struct elf_prstatus prstatus_t; -+typedef struct elf_prpsinfo prpsinfo_t; -+ -+__END_DECLS -+ -+#endif /* sys/procfs.h */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/sys/ucontext.h b/sysdeps/unix/sysv/linux/loongarch/sys/ucontext.h -new file mode 100644 -index 00000000..e52a46c9 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/sys/ucontext.h -@@ -0,0 +1,81 @@ -+/* Copyright (C) 2020-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 -+ . */ -+ -+/* Don't rely on this, the interface is currently messed up and may need to -+ be broken to be fixed. */ -+#ifndef _SYS_UCONTEXT_H -+#define _SYS_UCONTEXT_H 1 -+ -+#include -+ -+#include -+#include -+ -+typedef unsigned long int __loongarch_mc_gp_state[32]; -+ -+#ifdef __USE_MISC -+# define LARCH_NGREG 32 -+ -+# define LARCH_REG_RA 1 -+# define LARCH_REG_SP 3 -+# define LARCH_REG_S0 23 -+# define LARCH_REG_S1 24 -+# define LARCH_REG_A0 4 -+# define LARCH_REG_S2 25 -+# define LARCH_REG_NARGS 8 -+ -+typedef unsigned long int greg_t; -+ -+/* Container for all general registers. */ -+typedef __loongarch_mc_gp_state gregset_t; -+ -+/* Container for floating-point state. */ -+typedef union __loongarch_mc_fp_state fpregset_t; -+#endif -+ -+ -+ -+union __loongarch_mc_fp_state { -+ unsigned int __val32[256 / 32]; -+ unsigned long long __val64[256 / 64]; -+}; -+ -+typedef struct mcontext_t { -+ unsigned long long __pc; -+ unsigned long long __gregs[32]; -+ unsigned int __flags; -+ -+ unsigned int __fcsr; -+ unsigned int __vcsr; -+ unsigned long long __fcc; -+ union __loongarch_mc_fp_state __fpregs[32] __attribute__((__aligned__ (32))); -+ -+ unsigned int __reserved; -+} mcontext_t; -+ -+/* Userlevel context. */ -+typedef struct ucontext_t -+ { -+ unsigned long int __uc_flags; -+ struct ucontext_t *uc_link; -+ stack_t uc_stack; -+ mcontext_t uc_mcontext; -+ sigset_t uc_sigmask; -+ } ucontext_t; -+ -+#endif /* sys/ucontext.h */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/sys/user.h b/sysdeps/unix/sysv/linux/loongarch/sys/user.h -new file mode 100644 -index 00000000..f9108350 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/sys/user.h -@@ -0,0 +1,31 @@ -+/* Copyright (C) 2001-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#ifndef _SYS_USER_H -+#define _SYS_USER_H 1 -+ -+#include -+ -+struct user_regs_struct -+{ -+ uint64_t gpr[32]; -+ uint64_t pc; -+ uint64_t badvaddr; -+ uint64_t reserved[11]; -+}; -+ -+#endif /* _SYS_USER_H */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/syscall.c b/sysdeps/unix/sysv/linux/loongarch/syscall.c -new file mode 100644 -index 00000000..b06a528e ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/syscall.c -@@ -0,0 +1,36 @@ -+/* Copyright (C) 2020-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 -+ -+long int -+syscall (long int syscall_number, long int arg1, long int arg2, long int arg3, -+ long int arg4, long int arg5, long int arg6, long int arg7) -+{ -+ long int ret; -+ INTERNAL_SYSCALL_DECL (err); -+ -+ ret = INTERNAL_SYSCALL_NCS (syscall_number, err, 7, arg1, arg2, arg3, arg4, -+ arg5, arg6, arg7); -+ -+ if (INTERNAL_SYSCALL_ERROR_P (ret, err)) -+ return __syscall_error (ret); -+ -+ return ret; -+} -+ -diff --git a/sysdeps/unix/sysv/linux/loongarch/sysdep.S b/sysdeps/unix/sysv/linux/loongarch/sysdep.S -new file mode 100644 -index 00000000..a8094283 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/sysdep.S -@@ -0,0 +1,52 @@ -+/* syscall error handlers -+ Copyright (C) 2011-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#include -+ -+#if IS_IN (libc) -+# define errno __libc_errno -+#endif -+ -+ENTRY (__syscall_error) -+ /* Fall through to __syscall_set_errno. */ -+END (__syscall_error) -+ -+/* Non-standard calling convention: argument in a0, return address in t0, -+ and clobber only t1. */ -+ENTRY (__syscall_set_errno) -+ /* We got here because a0 < 0, but only codes in the range [-4095, -1] -+ represent errors. Otherwise, just return the result normally. */ -+ -+ li.d t1, -4096 -+ bgeu t1, a0, L (out) -+ sub.w a0, zero, a0 -+ -+#if RTLD_PRIVATE_ERRNO -+ la t1, rtld_errno -+#elif defined(__PIC__) -+ la.tls.ie t1, errno -+ add.d t1, tp, t1 -+#else -+ la.tls.le t1, errno -+ add.d t1, tp, t1 -+#endif -+ st.w a0, t1, 0 -+ li.d a0, -1 -+L (out): -+ ret -+END (__syscall_set_errno) -diff --git a/sysdeps/unix/sysv/linux/loongarch/sysdep.h b/sysdeps/unix/sysv/linux/loongarch/sysdep.h -new file mode 100644 -index 00000000..f50946d4 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/sysdep.h -@@ -0,0 +1,333 @@ -+#ifndef _LINUX_LOONGARCH_SYSDEP_H -+#define _LINUX_LOONGARCH_SYSDEP_H 1 -+ -+#include -+#include -+ -+#ifdef __ASSEMBLER__ -+ -+# include -+# define ret jirl zero, ra, 0 -+# define L(label) .L ## label -+ -+/* Performs a system call, handling errors by setting errno. Linux indicates -+ errors by setting a0 to a value between -1 and -4095. */ -+# undef PSEUDO -+# define PSEUDO(name, syscall_name, args) \ -+ ENTRY (name); \ -+ li.d a7, SYS_ify (syscall_name); \ -+ syscall 0; \ -+ li.d a7, -4096; \ -+ bltu a7, a0, .Lsyscall_error ## name; -+ -+# undef PSEUDO_END -+# define PSEUDO_END(sym) \ -+ SYSCALL_ERROR_HANDLER (sym); \ -+ ret; \ -+ END (sym); -+ -+# if !IS_IN (libc) -+# if RTLD_PRIVATE_ERRNO -+ -+# define SYSCALL_ERROR_HANDLER(name) \ -+.Lsyscall_error ## name: \ -+ la t0, rtld_errno; \ -+ sub.w a0, zero, a0; \ -+ st.w a0, t0, 0; \ -+ li.d a0, -1; -+ -+# else -+ -+# define SYSCALL_ERROR_HANDLER(name) \ -+.Lsyscall_error ## name: \ -+ la.tls.ie t0, errno; \ -+ add.d t0, tp, t0; \ -+ sub.w a0, zero, a0; \ -+ st.w a0, t0, 0; \ -+ li.d a0, -1; -+ -+# endif -+# else -+ -+# define SYSCALL_ERROR_HANDLER(name) \ -+.Lsyscall_error ## name: \ -+ b __syscall_error; -+ -+# endif -+ -+/* Performs a system call, not setting errno. */ -+# undef PSEUDO_NEORRNO -+# define PSEUDO_NOERRNO(name, syscall_name, args) \ -+ ENTRY (name); \ -+ li.d a7, SYS_ify (syscall_name); \ -+ syscall 0; -+ -+# undef PSEUDO_END_NOERRNO -+# define PSEUDO_END_NOERRNO(name) \ -+ END (name); -+ -+# undef ret_NOERRNO -+# define ret_NOERRNO ret -+ -+/* Perfroms a system call, returning the error code. */ -+# undef PSEUDO_ERRVAL -+# define PSEUDO_ERRVAL(name, syscall_name, args) \ -+ PSEUDO_NOERRNO (name, syscall_name, args); \ -+ slli.d a0, a0, 32; \ -+ srai.d a0, a0, 32; /* sign_ext */ \ -+ sub.d a0, zero, a0; -+ -+# undef PSEUDO_END_ERRVAL -+# define PSEUDO_END_ERRVAL(name) \ -+ END (name); -+ -+# undef ret_ERRVAL -+# define ret_ERRVAL ret -+ -+#endif /* __ASSEMBLER__ */ -+ -+/* In order to get __set_errno() definition in INLINE_SYSCALL. */ -+#ifndef __ASSEMBLER__ -+# include -+#endif -+ -+#include -+ -+#undef SYS_ify -+#define SYS_ify(syscall_name) __NR_##syscall_name -+ -+#ifndef __ASSEMBLER__ -+ -+/* List of system calls which are supported as vsyscalls. */ -+# define HAVE_CLOCK_GETRES_VSYSCALL 1 -+# define HAVE_CLOCK_GETTIME_VSYSCALL 1 -+# define HAVE_GETTIMEOFDAY_VSYSCALL 1 -+# define HAVE_GETCPU_VSYSCALL 1 -+ -+/* Define a macro which expands into the inline wrapper code for a system -+ call. */ -+# undef INLINE_SYSCALL -+# define INLINE_SYSCALL(name, nr, args...) \ -+ ({ INTERNAL_SYSCALL_DECL (err); \ -+ long int __sys_result = INTERNAL_SYSCALL (name, err, nr, args); \ -+ if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (__sys_result, ))) \ -+ { \ -+ __set_errno (INTERNAL_SYSCALL_ERRNO (__sys_result, )); \ -+ __sys_result = (unsigned long) -1; \ -+ } \ -+ __sys_result; }) -+ -+ -+# define INTERNAL_SYSCALL_DECL(err) do { } while (0) -+ -+# define INTERNAL_SYSCALL_ERROR_P(val, err) \ -+ ((unsigned long int) (val) > -4096UL) -+ -+# define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) -+ -+# define INTERNAL_SYSCALL(name, err, nr, args...) \ -+ internal_syscall##nr (SYS_ify (name), err, args) -+ -+# define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ -+ internal_syscall##nr (number, err, args) -+ -+# define internal_syscall0(number, err, dummy...) \ -+({ \ -+ long int _sys_result; \ -+ \ -+ { \ -+ register long int __a7 asm ("$a7") = number; \ -+ register long int __a0 asm ("$a0"); \ -+ __asm__ volatile ( \ -+ "syscall 0\n\t" \ -+ : "=r" (__a0) \ -+ : "r" (__a7) \ -+ : __SYSCALL_CLOBBERS); \ -+ _sys_result = __a0; \ -+ } \ -+ _sys_result; \ -+}) -+ -+# define internal_syscall1(number, err, arg0) \ -+({ \ -+ long int _sys_result; \ -+ \ -+ { \ -+ long int _arg0 = (long int) (arg0); \ -+ register long int __a7 asm ("$a7") = number; \ -+ register long int __a0 asm ("$a0") = _arg0; \ -+ __asm__ volatile ( \ -+ "syscall 0\n\t" \ -+ : "+r" (__a0) \ -+ : "r" (__a7) \ -+ : __SYSCALL_CLOBBERS); \ -+ _sys_result = __a0; \ -+ } \ -+ _sys_result; \ -+}) -+ -+# define internal_syscall2(number, err, arg0, arg1) \ -+({ \ -+ long int _sys_result; \ -+ \ -+ { \ -+ long int _arg0 = (long int) (arg0); \ -+ long int _arg1 = (long int) (arg1); \ -+ register long int __a7 asm ("$a7") = number; \ -+ register long int __a0 asm ("$a0") = _arg0; \ -+ register long int __a1 asm ("$a1") = _arg1; \ -+ __asm__ volatile ( \ -+ "syscall 0\n\t" \ -+ : "+r" (__a0) \ -+ : "r" (__a7), "r" (__a1) \ -+ : __SYSCALL_CLOBBERS); \ -+ _sys_result = __a0; \ -+ } \ -+ _sys_result; \ -+}) -+ -+# define internal_syscall3(number, err, arg0, arg1, arg2) \ -+({ \ -+ long int _sys_result; \ -+ \ -+ { \ -+ long int _arg0 = (long int) (arg0); \ -+ long int _arg1 = (long int) (arg1); \ -+ long int _arg2 = (long int) (arg2); \ -+ register long int __a7 asm ("$a7") = number; \ -+ register long int __a0 asm ("$a0") = _arg0; \ -+ register long int __a1 asm ("$a1") = _arg1; \ -+ register long int __a2 asm ("$a2") = _arg2; \ -+ __asm__ volatile ( \ -+ "syscall 0\n\t" \ -+ : "+r" (__a0) \ -+ : "r" (__a7), "r" (__a1), "r" (__a2) \ -+ : __SYSCALL_CLOBBERS); \ -+ _sys_result = __a0; \ -+ } \ -+ _sys_result; \ -+}) -+ -+# define internal_syscall4(number, err, arg0, arg1, arg2, arg3) \ -+({ \ -+ long int _sys_result; \ -+ \ -+ { \ -+ long int _arg0 = (long int) (arg0); \ -+ long int _arg1 = (long int) (arg1); \ -+ long int _arg2 = (long int) (arg2); \ -+ long int _arg3 = (long int) (arg3); \ -+ register long int __a7 asm ("$a7") = number; \ -+ register long int __a0 asm ("$a0") = _arg0; \ -+ register long int __a1 asm ("$a1") = _arg1; \ -+ register long int __a2 asm ("$a2") = _arg2; \ -+ register long int __a3 asm ("$a3") = _arg3; \ -+ __asm__ volatile ( \ -+ "syscall 0\n\t" \ -+ : "+r" (__a0) \ -+ : "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3) \ -+ : __SYSCALL_CLOBBERS); \ -+ _sys_result = __a0; \ -+ } \ -+ _sys_result; \ -+}) -+ -+# define internal_syscall5(number, err, arg0, arg1, arg2, arg3, arg4) \ -+({ \ -+ long int _sys_result; \ -+ \ -+ { \ -+ long int _arg0 = (long int) (arg0); \ -+ long int _arg1 = (long int) (arg1); \ -+ long int _arg2 = (long int) (arg2); \ -+ long int _arg3 = (long int) (arg3); \ -+ long int _arg4 = (long int) (arg4); \ -+ register long int __a7 asm ("$a7") = number; \ -+ register long int __a0 asm ("$a0") = _arg0; \ -+ register long int __a1 asm ("$a1") = _arg1; \ -+ register long int __a2 asm ("$a2") = _arg2; \ -+ register long int __a3 asm ("$a3") = _arg3; \ -+ register long int __a4 asm ("$a4") = _arg4; \ -+ __asm__ volatile ( \ -+ "syscall 0\n\t" \ -+ : "+r" (__a0) \ -+ : "r" (__a7), "r"(__a1), "r"(__a2), "r"(__a3), "r" (__a4) \ -+ : __SYSCALL_CLOBBERS); \ -+ _sys_result = __a0; \ -+ } \ -+ _sys_result; \ -+}) -+ -+# define internal_syscall6(number, err, arg0, arg1, arg2, arg3, arg4, arg5) \ -+({ \ -+ long int _sys_result; \ -+ \ -+ { \ -+ long int _arg0 = (long int) (arg0); \ -+ long int _arg1 = (long int) (arg1); \ -+ long int _arg2 = (long int) (arg2); \ -+ long int _arg3 = (long int) (arg3); \ -+ long int _arg4 = (long int) (arg4); \ -+ long int _arg5 = (long int) (arg5); \ -+ register long int __a7 asm ("$a7") = number; \ -+ register long int __a0 asm ("$a0") = _arg0; \ -+ register long int __a1 asm ("$a1") = _arg1; \ -+ register long int __a2 asm ("$a2") = _arg2; \ -+ register long int __a3 asm ("$a3") = _arg3; \ -+ register long int __a4 asm ("$a4") = _arg4; \ -+ register long int __a5 asm ("$a5") = _arg5; \ -+ __asm__ volatile ( \ -+ "syscall 0\n\t" \ -+ : "+r" (__a0) \ -+ : "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3), \ -+ "r" (__a4), "r" (__a5) \ -+ : __SYSCALL_CLOBBERS); \ -+ _sys_result = __a0; \ -+ } \ -+ _sys_result; \ -+}) -+ -+# define internal_syscall7(number, err, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \ -+({ \ -+ long int _sys_result; \ -+ \ -+ { \ -+ long int _arg0 = (long int) (arg0); \ -+ long int _arg1 = (long int) (arg1); \ -+ long int _arg2 = (long int) (arg2); \ -+ long int _arg3 = (long int) (arg3); \ -+ long int _arg4 = (long int) (arg4); \ -+ long int _arg5 = (long int) (arg5); \ -+ long int _arg6 = (long int) (arg6); \ -+ register long int __a7 asm ("$a7") = number; \ -+ register long int __a0 asm ("$a0") = _arg0; \ -+ register long int __a1 asm ("$a1") = _arg1; \ -+ register long int __a2 asm ("$a2") = _arg2; \ -+ register long int __a3 asm ("$a3") = _arg3; \ -+ register long int __a4 asm ("$a4") = _arg4; \ -+ register long int __a5 asm ("$a5") = _arg5; \ -+ register long int __a6 asm ("$a6") = _arg6; \ -+ __asm__ volatile ( \ -+ "syscall 0\n\t" \ -+ : "+r" (__a0) \ -+ : "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3), \ -+ "r" (__a4), "r" (__a5), "r" (__a6) \ -+ : __SYSCALL_CLOBBERS); \ -+ _sys_result = __a0; \ -+ } \ -+ _sys_result; \ -+}) -+ -+# define __SYSCALL_CLOBBERS \ -+ "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8",\ -+ "memory" -+ -+extern long int __syscall_error (long int neg_errno); -+ -+#endif /* ! __ASSEMBLER__ */ -+ -+/* Pointer mangling is not supported. */ -+#define PTR_MANGLE(var) (void) (var) -+#define PTR_DEMANGLE(var) (void) (var) -+ -+#endif /* linux/loongarch/sysdep.h */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/ucontext-macros.h b/sysdeps/unix/sysv/linux/loongarch/ucontext-macros.h -new file mode 100644 -index 00000000..abd22247 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/ucontext-macros.h -@@ -0,0 +1,44 @@ -+/* Macros for ucontext routines. -+ Copyright (C) 2017-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#ifndef _LINUX_LOONGARCH_UCONTEXT_MACROS_H -+#define _LINUX_LOONGARCH_UCONTEXT_MACROS_H -+ -+#include -+#include -+ -+#include "ucontext_i.h" -+ -+#define SAVE_FP_REG(name, num, base) \ -+ FREG_S name, base, ((num) * SZFREG + MCONTEXT_FPREGS) -+ -+#define RESTORE_FP_REG(name, num, base) \ -+ FREG_L name, base, ((num) * SZFREG + MCONTEXT_FPREGS) -+ -+#define SAVE_INT_REG(name, num, base) \ -+ REG_S name, base, ((num) * SZREG + MCONTEXT_GREGS) -+ -+#define RESTORE_INT_REG(name, num, base) \ -+ REG_L name, base, ((num) * SZREG + MCONTEXT_GREGS) -+ -+#define SAVE_REG(name, offset, base) \ -+ REG_S name, base, (offset) -+ -+#define RESTORE_REG(name, offset, base) \ -+ REG_L name, base, (offset) -+#endif /* _LINUX_LOONGARCH_UCONTEXT_MACROS_H */ -diff --git a/sysdeps/unix/sysv/linux/loongarch/ucontext_i.sym b/sysdeps/unix/sysv/linux/loongarch/ucontext_i.sym -new file mode 100644 -index 00000000..d7f612fe ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/ucontext_i.sym -@@ -0,0 +1,33 @@ -+#include -+#include -+#include -+#include -+ -+-- Constants used by the rt_sigprocmask call. -+ -+SIG_BLOCK -+SIG_SETMASK -+ -+_NSIG8 (_NSIG / 8) -+ -+-- Offsets of the fields in the ucontext_t structure. -+#define ucontext(member) offsetof (ucontext_t, member) -+#define stack(member) ucontext (uc_stack.member) -+#define mcontext(member) ucontext (uc_mcontext.member) -+ -+UCONTEXT_FLAGS ucontext (__uc_flags) -+UCONTEXT_LINK ucontext (uc_link) -+UCONTEXT_STACK ucontext (uc_stack) -+UCONTEXT_MCONTEXT ucontext (uc_mcontext) -+UCONTEXT_SIGMASK ucontext (uc_sigmask) -+ -+STACK_SP stack (ss_sp) -+STACK_SIZE stack (ss_size) -+STACK_FLAGS stack (ss_flags) -+ -+MCONTEXT_PC mcontext (__pc) -+MCONTEXT_FCSR mcontext (__fcsr) -+MCONTEXT_GREGS mcontext (__gregs) -+MCONTEXT_FPREGS mcontext (__fpregs) -+ -+UCONTEXT_SIZE sizeof (ucontext_t) -diff --git a/sysdeps/unix/sysv/linux/loongarch/vfork.S b/sysdeps/unix/sysv/linux/loongarch/vfork.S -new file mode 100644 -index 00000000..83cf141f ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/loongarch/vfork.S -@@ -0,0 +1,49 @@ -+/* Copyright (C) 1999-2018 Free Software Foundation, Inc. -+ -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of the -+ License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#define _ERRNO_H 1 -+#include -+ -+/* Clone the calling process, but without copying the whole address space. -+ The calling process is suspended until the new process exits or is -+ replaced by a call to `execve'. Return -1 for errors, 0 to the new process, -+ and the process ID of the new process to the old process. */ -+ -+ENTRY (__vfork) -+ -+ -+ li.d a0, 0x4111 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ -+ add.d a1, zero, sp -+ -+ /* Do the system call. */ -+ li.d a7, __NR_clone -+ syscall 0 -+ -+ blt a0, zero ,L (error) -+ -+ ret -+ -+L (error): -+ b __syscall_error -+ END (__vfork) -+ -+libc_hidden_def (__vfork) -+ -+weak_alias (__vfork, vfork) -+strong_alias (__vfork, __libc_vfork) --- -2.20.1 - diff --git a/glibc-Properly-check-stack-alignment-BZ-27901.patch b/glibc-Properly-check-stack-alignment-BZ-27901.patch deleted file mode 100644 index 58b6c5f..0000000 --- a/glibc-Properly-check-stack-alignment-BZ-27901.patch +++ /dev/null @@ -1,325 +0,0 @@ -From 7ae4fdd1783cdfd30bfefdd7c3c3c9430f234406 Mon Sep 17 00:00:00 2001 -From: "H.J. Lu" -Date: Tue, 15 Feb 2022 14:15:50 -0500 -Subject: [PATCH] Properly check stack alignment [BZ #27901] - -1. Replace - -if ((((uintptr_t) &_d) & (__alignof (double) - 1)) != 0) - -which may be optimized out by compiler, with - -int -__attribute__ ((weak, noclone, noinline)) -is_aligned (void *p, int align) -{ - return (((uintptr_t) p) & (align - 1)) != 0; -} - -2. Add TEST_STACK_ALIGN_INIT to TEST_STACK_ALIGN. -3. Add a common TEST_STACK_ALIGN_INIT to check 16-byte stack alignment -for both i386 and x86-64. -4. Update powerpc to use TEST_STACK_ALIGN_INIT. - -Reviewed-by: Carlos O'Donell -Signed-off-by: Rongwei Wang ---- - sysdeps/generic/tst-stack-align.h | 40 ++++++++++++++++--------- - sysdeps/i386/i686/tst-stack-align.h | 44 --------------------------- - sysdeps/i386/tst-stack-align.h | 41 ------------------------- - sysdeps/powerpc/tst-stack-align.h | 27 +++++------------ - sysdeps/x86/tst-stack-align.h | 28 ++++++++++++++++++ - sysdeps/x86_64/tst-stack-align.h | 46 ----------------------------- - 6 files changed, 61 insertions(+), 165 deletions(-) - delete mode 100644 sysdeps/i386/i686/tst-stack-align.h - delete mode 100644 sysdeps/i386/tst-stack-align.h - create mode 100644 sysdeps/x86/tst-stack-align.h - delete mode 100644 sysdeps/x86_64/tst-stack-align.h - -diff --git a/sysdeps/generic/tst-stack-align.h b/sysdeps/generic/tst-stack-align.h -index e5cb3310..e6050901 100644 ---- a/sysdeps/generic/tst-stack-align.h -+++ b/sysdeps/generic/tst-stack-align.h -@@ -1,4 +1,5 @@ --/* Copyright (C) 2003-2018 Free Software Foundation, Inc. -+/* Check stack alignment. Generic version. -+ Copyright (C) 2003-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 -@@ -18,17 +19,28 @@ - #include - #include - -+int -+__attribute__ ((weak, noclone, noinline)) -+is_aligned (void *p, int align) -+{ -+ return (((uintptr_t) p) & (align - 1)) != 0; -+} -+ -+#ifndef TEST_STACK_ALIGN_INIT -+# define TEST_STACK_ALIGN_INIT() 0 -+#endif -+ - #define TEST_STACK_ALIGN() \ -- ({ \ -- double _d = 12.0; \ -- long double _ld = 15.0; \ -- int _ret = 0; \ -- printf ("double: %g %p %zu\n", _d, &_d, __alignof (double)); \ -- if ((((uintptr_t) &_d) & (__alignof (double) - 1)) != 0) \ -- _ret = 1; \ -- \ -- printf ("ldouble: %Lg %p %zu\n", _ld, &_ld, __alignof (long double)); \ -- if ((((uintptr_t) &_ld) & (__alignof (long double) - 1)) != 0) \ -- _ret = 1; \ -- _ret; \ -- }) -+ ({ \ -+ double _d = 12.0; \ -+ long double _ld = 15.0; \ -+ int _ret = TEST_STACK_ALIGN_INIT (); \ -+ \ -+ printf ("double: %g %p %zu\n", _d, &_d, __alignof (double)); \ -+ _ret += is_aligned (&_d, __alignof (double)); \ -+ \ -+ printf ("ldouble: %Lg %p %zu\n", _ld, &_ld, \ -+ __alignof (long double)); \ -+ _ret += is_aligned (&_ld, __alignof (long double)); \ -+ _ret; \ -+ }) -diff --git a/sysdeps/i386/i686/tst-stack-align.h b/sysdeps/i386/i686/tst-stack-align.h -deleted file mode 100644 -index 975f26ef..00000000 ---- a/sysdeps/i386/i686/tst-stack-align.h -+++ /dev/null -@@ -1,44 +0,0 @@ --/* Copyright (C) 2003-2018 Free Software Foundation, Inc. -- This file is part of the GNU C Library. -- -- The GNU C Library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- The GNU C Library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with the GNU C Library; if not, see -- . */ -- --#include --#include --#ifndef __SSE__ --#include_next --#else --#include -- --#define TEST_STACK_ALIGN() \ -- ({ \ -- __m128 _m; \ -- double _d = 12.0; \ -- long double _ld = 15.0; \ -- int _ret = 0; \ -- printf ("__m128: %p %zu\n", &_m, __alignof (__m128)); \ -- if ((((uintptr_t) &_m) & (__alignof (__m128) - 1)) != 0) \ -- _ret = 1; \ -- \ -- printf ("double: %g %p %zu\n", _d, &_d, __alignof (double)); \ -- if ((((uintptr_t) &_d) & (__alignof (double) - 1)) != 0) \ -- _ret = 1; \ -- \ -- printf ("ldouble: %Lg %p %zu\n", _ld, &_ld, __alignof (long double)); \ -- if ((((uintptr_t) &_ld) & (__alignof (long double) - 1)) != 0) \ -- _ret = 1; \ -- _ret; \ -- }) --#endif -diff --git a/sysdeps/i386/tst-stack-align.h b/sysdeps/i386/tst-stack-align.h -deleted file mode 100644 -index 394ff773..00000000 ---- a/sysdeps/i386/tst-stack-align.h -+++ /dev/null -@@ -1,41 +0,0 @@ --/* Copyright (C) 2004-2018 Free Software Foundation, Inc. -- This file is part of the GNU C Library. -- -- The GNU C Library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- The GNU C Library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with the GNU C Library; if not, see -- . */ -- --#include --#include -- --typedef struct { int i[4]; } int_al16 __attribute__((aligned (16))); -- --#define TEST_STACK_ALIGN() \ -- ({ \ -- int_al16 _m; \ -- double _d = 12.0; \ -- long double _ld = 15.0; \ -- int _ret = 0; \ -- printf ("int_al16: %p %zu\n", &_m, __alignof (int_al16)); \ -- if ((((uintptr_t) &_m) & (__alignof (int_al16) - 1)) != 0) \ -- _ret = 1; \ -- \ -- printf ("double: %g %p %zu\n", _d, &_d, __alignof (double)); \ -- if ((((uintptr_t) &_d) & (__alignof (double) - 1)) != 0) \ -- _ret = 1; \ -- \ -- printf ("ldouble: %Lg %p %zu\n", _ld, &_ld, __alignof (long double)); \ -- if ((((uintptr_t) &_ld) & (__alignof (long double) - 1)) != 0) \ -- _ret = 1; \ -- _ret; \ -- }) -diff --git a/sysdeps/powerpc/tst-stack-align.h b/sysdeps/powerpc/tst-stack-align.h -index 7fd7013b..d7400b28 100644 ---- a/sysdeps/powerpc/tst-stack-align.h -+++ b/sysdeps/powerpc/tst-stack-align.h -@@ -1,4 +1,5 @@ --/* Copyright (C) 2005-2018 Free Software Foundation, Inc. -+/* Check stack alignment. PowerPC version. -+ Copyright (C) 2005-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 -@@ -15,10 +16,7 @@ - License along with the GNU C Library; if not, see - . */ - --#include --#include -- --#define TEST_STACK_ALIGN() \ -+#define TEST_STACK_ALIGN_INIT() \ - ({ \ - /* Altivec __vector int etc. needs 16byte aligned stack. \ - Instead of using altivec.h here, use aligned attribute instead. */ \ -@@ -27,20 +25,9 @@ - int _i __attribute__((aligned (16))); \ - int _j[3]; \ - } _s = { ._i = 18, ._j[0] = 19, ._j[1] = 20, ._j[2] = 21 }; \ -- double _d = 12.0; \ -- long double _ld = 15.0; \ -- int _ret = 0; \ - printf ("__vector int: { %d, %d, %d, %d } %p %zu\n", _s._i, _s._j[0], \ - _s._j[1], _s._j[2], &_s, __alignof (_s)); \ -- if ((((uintptr_t) &_s) & (__alignof (_s) - 1)) != 0) \ -- _ret = 1; \ -- \ -- printf ("double: %g %p %zu\n", _d, &_d, __alignof (double)); \ -- if ((((uintptr_t) &_d) & (__alignof (double) - 1)) != 0) \ -- _ret = 1; \ -- \ -- printf ("ldouble: %Lg %p %zu\n", _ld, &_ld, __alignof (long double)); \ -- if ((((uintptr_t) &_ld) & (__alignof (long double) - 1)) != 0) \ -- _ret = 1; \ -- _ret; \ -- }) -+ is_aligned (&_s, __alignof (_s)); \ -+ }) -+ -+#include_next -diff --git a/sysdeps/x86/tst-stack-align.h b/sysdeps/x86/tst-stack-align.h -new file mode 100644 -index 00000000..02ecc72d ---- /dev/null -+++ b/sysdeps/x86/tst-stack-align.h -@@ -0,0 +1,28 @@ -+/* Check stack alignment. X86 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 -+ . */ -+ -+typedef struct { int i[16]; } int_al16 __attribute__((aligned (16))); -+ -+#define TEST_STACK_ALIGN_INIT() \ -+ ({ \ -+ int_al16 _m; \ -+ printf ("int_al16: %p %zu\n", &_m, __alignof (int_al16)); \ -+ is_aligned (&_m, __alignof (int_al16)); \ -+ }) -+ -+#include_next -diff --git a/sysdeps/x86_64/tst-stack-align.h b/sysdeps/x86_64/tst-stack-align.h -deleted file mode 100644 -index b2ef77f6..00000000 ---- a/sysdeps/x86_64/tst-stack-align.h -+++ /dev/null -@@ -1,46 +0,0 @@ --/* Copyright (C) 2003-2018 Free Software Foundation, Inc. -- This file is part of the GNU C Library. -- -- The GNU C Library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- The GNU C Library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with the GNU C Library; if not, see -- . */ -- --#include --#include -- --#define TEST_STACK_ALIGN() \ -- ({ \ -- /* AMD64 ABI mandates 16byte aligned stack. \ -- Unfortunately, current GCC doesn't support __int128 or __float128 \ -- types, so use aligned attribute instead. */ \ -- struct _S \ -- { \ -- int _i __attribute__((aligned (16))); \ -- int _pad[3]; \ -- } _s = { ._i = 18 }; \ -- double _d = 12.0; \ -- long double _ld = 15.0; \ -- int _ret = 0; \ -- printf ("__int128: %d %p %zu\n", _s._i, &_s, __alignof (_s)); \ -- if ((((uintptr_t) &_s) & (__alignof (_s) - 1)) != 0) \ -- _ret = 1; \ -- \ -- printf ("double: %g %p %zu\n", _d, &_d, __alignof (double)); \ -- if ((((uintptr_t) &_d) & (__alignof (double) - 1)) != 0) \ -- _ret = 1; \ -- \ -- printf ("ldouble: %Lg %p %zu\n", _ld, &_ld, __alignof (long double)); \ -- if ((((uintptr_t) &_ld) & (__alignof (long double) - 1)) != 0) \ -- _ret = 1; \ -- _ret; \ -- }) --- -2.18.4 - diff --git a/glibc-Support-target-specific-ALIGN-for-variable-alignment-4.patch b/glibc-Support-target-specific-ALIGN-for-variable-alignment-4.patch deleted file mode 100644 index 5ac2055..0000000 --- a/glibc-Support-target-specific-ALIGN-for-variable-alignment-4.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 9302aaad29363eb1dba30d5b9b588a165395672a Mon Sep 17 00:00:00 2001 -From: "H.J. Lu" -Date: Mon, 7 Feb 2022 10:46:19 -0500 -Subject: [PATCH 4/4] Support target specific ALIGN for variable alignment test - [BZ #28676] - -Add to support target specific ALIGN for variable -alignment test: - -1. Alpha: Use 0x10000. -2. MicroBlaze and Nios II: Use 0x8000. -3. All others: Use 0x200000. - -Backport from master commit: 4435c29 - -Reviewed-by: Adhemerval Zanella -Signed-off-by: Rongwei Wang ---- - elf/tst-align3.c | 4 +--- - elf/tst-alignmod3.c | 4 +--- - sysdeps/alpha/tst-file-align.h | 20 ++++++++++++++++++++ - sysdeps/generic/tst-file-align.h | 20 ++++++++++++++++++++ - sysdeps/microblaze/tst-file-align.h | 20 ++++++++++++++++++++ - sysdeps/nios2/tst-file-align.h | 20 ++++++++++++++++++++ - 6 files changed, 82 insertions(+), 6 deletions(-) - create mode 100644 sysdeps/alpha/tst-file-align.h - create mode 100644 sysdeps/generic/tst-file-align.h - create mode 100644 sysdeps/microblaze/tst-file-align.h - create mode 100644 sysdeps/nios2/tst-file-align.h - -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 @@ - . */ - - #include -+#include - #include - --/* This should cover all possible page sizes we currently support. */ --#define ALIGN 0x200000 -- - 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 @@ - . */ - - #include -+#include - #include - --/* This should cover all possible page sizes we currently support. */ --#define ALIGN 0x200000 -- - 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 ---- /dev/null -+++ b/sysdeps/alpha/tst-file-align.h -@@ -0,0 +1,20 @@ -+/* Check file alignment. Alpha 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 -+ . */ -+ -+/* This should cover all possible alignments we currently support. */ -+#define ALIGN 0x10000 -diff --git a/sysdeps/generic/tst-file-align.h b/sysdeps/generic/tst-file-align.h -new file mode 100644 -index 00000000..6ee6783a ---- /dev/null -+++ b/sysdeps/generic/tst-file-align.h -@@ -0,0 +1,20 @@ -+/* Check file alignment. Generic 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 -+ . */ -+ -+/* This should cover all possible page sizes we currently support. */ -+#define ALIGN 0x200000 -diff --git a/sysdeps/microblaze/tst-file-align.h b/sysdeps/microblaze/tst-file-align.h -new file mode 100644 -index 00000000..43c58b29 ---- /dev/null -+++ b/sysdeps/microblaze/tst-file-align.h -@@ -0,0 +1,20 @@ -+/* Check file alignment. MicroBlaze 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 -+ . */ -+ -+/* This should cover all possible alignments we currently support. */ -+#define ALIGN 0x8000 -diff --git a/sysdeps/nios2/tst-file-align.h b/sysdeps/nios2/tst-file-align.h -new file mode 100644 -index 00000000..589a2d5a ---- /dev/null -+++ b/sysdeps/nios2/tst-file-align.h -@@ -0,0 +1,20 @@ -+/* Check file alignment. Nios II 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 -+ . */ -+ -+/* This should cover all possible alignments we currently support. */ -+#define ALIGN 0x8000 --- -2.18.4 - diff --git a/glibc-bz29016.patch b/glibc-bz29016.patch deleted file mode 100644 index bf5324f..0000000 --- a/glibc-bz29016.patch +++ /dev/null @@ -1,177 +0,0 @@ -From e7223fa1e8e0673440cc62364b67d55afc78123a Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella -Date: Tue, 6 Dec 2022 13:28:40 -0300 -Subject: [PATCH] stdio: Do not ignore posix_spawn error on popen (BZ #29016) - -To correctly return error in case of default shell is not present. - -Checked on x86_64-linux-gnu. ---- - libio/iopopen.c | 38 ++++++++++++++++++++++---------------- - stdio-common/Makefile | 3 +++ - stdio-common/tst-popen3.c | 38 ++++++++++++++++++++++++++++++++++++++ - 3 files changed, 63 insertions(+), 16 deletions(-) - create mode 100644 stdio-common/tst-popen3.c - -diff --git a/libio/iopopen.c b/libio/iopopen.c -index 10b0503c23..d0545ad5ea 100644 ---- a/libio/iopopen.c -+++ b/libio/iopopen.c -@@ -66,11 +66,12 @@ unlock (void *not_used) - be close (by transversing the proc_file_chain list) and the insertion of a - new one after a successful posix_spawn this function should be called - with proc_file_chain_lock acquired. */ --static bool -+static int - spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command, - int do_cloexec, int pipe_fds[2], int parent_end, int child_end, - int child_pipe_fd) - { -+ int err = 0; - - for (struct _IO_proc_file *p = proc_file_chain; p; p = p->next) - { -@@ -79,15 +80,19 @@ spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command, - /* If any stream from previous popen() calls has fileno - child_pipe_fd, it has been already closed by the adddup2 action - above. */ -- if (fd != child_pipe_fd -- && __posix_spawn_file_actions_addclose (fa, fd) != 0) -- return false; -+ if (fd != child_pipe_fd) -+ { -+ err = __posix_spawn_file_actions_addclose (fa, fd); -+ if (err != 0) -+ return err; -+ } - } - -- if (__posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0, -- (char *const[]){ (char*) "sh", (char*) "-c", -- (char *) command, NULL }, __environ) != 0) -- return false; -+ err = __posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0, -+ (char *const[]){ (char*) "sh", (char*) "-c", -+ (char *) command, NULL }, __environ); -+ if (err != 0) -+ return err; - - __close_nocancel (pipe_fds[child_end]); - -@@ -101,7 +106,7 @@ spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command, - ((_IO_proc_file *) fp)->next = proc_file_chain; - proc_file_chain = (_IO_proc_file *) fp; - -- return true; -+ return 0; - } - - FILE * -@@ -112,7 +117,7 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode) - int parent_end, child_end; - int pipe_fds[2]; - int child_pipe_fd; -- bool spawn_ok; -+ int err; - - int do_read = 0; - int do_write = 0; -@@ -185,16 +190,17 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode) - pipe_fds[child_end] = tmp; - } - -- if (__posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end], -- child_pipe_fd) != 0) -+ err = __posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end], -+ child_pipe_fd); -+ if (err != 0) - goto spawn_failure; - - #ifdef _IO_MTSAFE_IO - _IO_cleanup_region_start_noarg (unlock); - _IO_lock_lock (proc_file_chain_lock); - #endif -- spawn_ok = spawn_process (&fa, fp, command, do_cloexec, pipe_fds, -- parent_end, child_end, child_pipe_fd); -+ err = spawn_process (&fa, fp, command, do_cloexec, pipe_fds, parent_end, -+ child_end, child_pipe_fd); - #ifdef _IO_MTSAFE_IO - _IO_lock_unlock (proc_file_chain_lock); - _IO_cleanup_region_end (0); -@@ -202,12 +208,12 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode) - - __posix_spawn_file_actions_destroy (&fa); - -- if (!spawn_ok) -+ if (err != 0) - { -+ __set_errno (err); - spawn_failure: - __close_nocancel (pipe_fds[child_end]); - __close_nocancel (pipe_fds[parent_end]); -- __set_errno (ENOMEM); - return NULL; - } - -diff --git a/stdio-common/Makefile b/stdio-common/Makefile -index a10f12a..d885c4a 100644 ---- a/stdio-common/Makefile -+++ b/stdio-common/Makefile -@@ -64,6 +64,9 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ - tst-scanf-round \ - tst-renameat2 \ - -+tests-container += \ -+ tst-popen3 -+ - test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble - - ifeq ($(run-built-tests),yes) - -diff --git a/stdio-common/tst-popen3.c b/stdio-common/tst-popen3.c -new file mode 100644 -index 0000000000..add5e97c09 ---- /dev/null -+++ b/stdio-common/tst-popen3.c -@@ -0,0 +1,38 @@ -+/* Check if popen return a correct error code if the default shell does not -+ exists (BZ#29016). -+ -+ 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 -+ -+int -+do_test (void) -+{ -+ xunlink (_PATH_BSHELL); -+ -+ FILE *f = popen ("/non-existent", "r"); -+ TEST_VERIFY (f == NULL); -+ TEST_COMPARE (errno, ENOENT); -+ return 0; -+} -+ -+#include --- -2.31.1 - diff --git a/glibc-elf-Align-argument-of-__munmap-to-page-size-BZ-28676-3.patch b/glibc-elf-Align-argument-of-__munmap-to-page-size-BZ-28676-3.patch deleted file mode 100644 index c065572..0000000 --- a/glibc-elf-Align-argument-of-__munmap-to-page-size-BZ-28676-3.patch +++ /dev/null @@ -1,36 +0,0 @@ -From a36e3f474b748bec447de3bdd8483b52b09e5804 Mon Sep 17 00:00:00 2001 -From: "H.J. Lu" -Date: Thu, 13 Jan 2022 03:48:36 +0800 -Subject: [PATCH 3/4] elf: Align argument of __munmap to page size [BZ #28676] - -On Linux/x86-64, for elf/tst-align3, we now get - -munmap(0x7f88f9401000, 1126424) = 0 - -instead of - -munmap(0x7f1615200018, 544768) = -1 EINVAL (Invalid argument) - -Backport from master commit: fd6062e - -Reviewed-by: Florian Weimer -Signed-off-by: Rongwei Wang ---- - elf/dl-map-segments.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h -index 61ba04cd..f1f7ad88 100644 ---- a/elf/dl-map-segments.h -+++ b/elf/dl-map-segments.h -@@ -55,6 +55,7 @@ _dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref, - if (delta) - __munmap ((void *) map_start, delta); - ElfW(Addr) map_end = map_start_aligned + maplength; -+ map_end = ALIGN_UP (map_end, GLRO(dl_pagesize)); - delta = map_start + maplen - map_end; - if (delta) - __munmap ((void *) map_end, delta); --- -2.18.4 - diff --git a/glibc-elf-Fix-tst-align3.patch b/glibc-elf-Fix-tst-align3.patch deleted file mode 100644 index c170b2c..0000000 --- a/glibc-elf-Fix-tst-align3.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 716c4027b04db785034b0f67ac552cfaff360463 Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella -Date: Tue, 18 Jan 2022 14:36:45 -0300 -Subject: [PATCH] elf: Fix tst-align3 - -The elf/tst-align3.c declares the function using a wrong prototype. - -Checked on aarch64-linux-gnu. - -Signed-off-by: Rongwei Wang ---- - elf/tst-align3.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/elf/tst-align3.c b/elf/tst-align3.c -index 4913c26..6853b6e 100644 ---- a/elf/tst-align3.c -+++ b/elf/tst-align3.c -@@ -22,7 +22,7 @@ - - int bar __attribute__ ((aligned (ALIGN))) = 1; - --extern int do_load_test (void); -+extern void do_load_test (void); - - static int - do_test (void) -@@ -30,7 +30,8 @@ do_test (void) - printf ("bar: %p\n", &bar); - TEST_VERIFY (is_aligned (&bar, ALIGN) == 0); - -- return do_load_test (); -+ do_load_test (); -+ return 0; - } - - #include --- -1.8.3.1 - diff --git a/glibc-elf-Properly-align-PT_LOAD-segments-BZ-28676-1.patch b/glibc-elf-Properly-align-PT_LOAD-segments-BZ-28676-1.patch deleted file mode 100644 index af6b6a6..0000000 --- a/glibc-elf-Properly-align-PT_LOAD-segments-BZ-28676-1.patch +++ /dev/null @@ -1,137 +0,0 @@ -From c61fc02c61a88204a5af47f61c1b7cfb19b61e32 Mon Sep 17 00:00:00 2001 -From: Rongwei Wang -Date: Mon, 7 Feb 2022 10:42:01 -0500 -Subject: [PATCH 1/4] elf: Properly align PT_LOAD segments [BZ #28676] - -When PT_LOAD segment alignment > the page size, allocate enough space to -ensure that the segment can be properly aligned. This change helps code -segments use huge pages become simple and available. - -This fixes [BZ #28676]. - -Backport from master commit: 718fdd8 - -Signed-off-by: Xu Yu -Signed-off-by: Rongwei Wang ---- - elf/dl-load.c | 2 ++ - elf/dl-load.h | 3 ++- - elf/dl-map-segments.h | 50 +++++++++++++++++++++++++++++++++++++++---- - 3 files changed, 50 insertions(+), 5 deletions(-) - -diff --git a/elf/dl-load.c b/elf/dl-load.c -index fee08d78..6785a499 100644 ---- a/elf/dl-load.c -+++ b/elf/dl-load.c -@@ -1,5 +1,6 @@ - /* Map in a shared object's segments from the file. - Copyright (C) 1995-2018 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 -@@ -1107,6 +1108,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, - c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize)); - c->dataend = ph->p_vaddr + ph->p_filesz; - c->allocend = ph->p_vaddr + ph->p_memsz; -+ c->mapalign = ph->p_align; - c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize)); - - /* Determine whether there is a gap between the last segment -diff --git a/elf/dl-load.h b/elf/dl-load.h -index 66ea2e92..d9f648ea 100644 ---- a/elf/dl-load.h -+++ b/elf/dl-load.h -@@ -1,5 +1,6 @@ - /* Map in a shared object's segments from the file. - Copyright (C) 1995-2018 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 -@@ -74,7 +75,7 @@ ELF_PREFERRED_ADDRESS_DATA; - Its details have been expanded out and converted. */ - struct loadcmd - { -- ElfW(Addr) mapstart, mapend, dataend, allocend; -+ ElfW(Addr) mapstart, mapend, dataend, allocend, mapalign; - ElfW(Off) mapoff; - int prot; /* PROT_* bits. */ - }; -diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h -index 084076a2..61ba04cd 100644 ---- a/elf/dl-map-segments.h -+++ b/elf/dl-map-segments.h -@@ -1,5 +1,6 @@ - /* Map in a shared object's segments. Generic version. - Copyright (C) 1995-2018 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 -@@ -18,6 +19,50 @@ - - #include - -+/* Map a segment and align it properly. */ -+ -+static __always_inline ElfW(Addr) -+_dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref, -+ const size_t maplength, int fd) -+{ -+ if (__glibc_likely (c->mapalign <= GLRO(dl_pagesize))) -+ return (ElfW(Addr)) __mmap ((void *) mappref, maplength, c->prot, -+ MAP_COPY|MAP_FILE, fd, c->mapoff); -+ -+ /* If the segment alignment > the page size, allocate enough space to -+ ensure that the segment can be properly aligned. */ -+ ElfW(Addr) maplen = (maplength >= c->mapalign -+ ? (maplength + c->mapalign) -+ : (2 * c->mapalign)); -+ ElfW(Addr) map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplen, -+ PROT_NONE, -+ MAP_ANONYMOUS|MAP_PRIVATE, -+ -1, 0); -+ if (__glibc_unlikely ((void *) map_start == MAP_FAILED)) -+ return map_start; -+ -+ ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, c->mapalign); -+ map_start_aligned = (ElfW(Addr)) __mmap ((void *) map_start_aligned, -+ maplength, c->prot, -+ MAP_COPY|MAP_FILE|MAP_FIXED, -+ fd, c->mapoff); -+ if (__glibc_unlikely ((void *) map_start_aligned == MAP_FAILED)) -+ __munmap ((void *) map_start, maplen); -+ else -+ { -+ /* Unmap the unused regions. */ -+ ElfW(Addr) delta = map_start_aligned - map_start; -+ if (delta) -+ __munmap ((void *) map_start, delta); -+ ElfW(Addr) map_end = map_start_aligned + maplength; -+ delta = map_start + maplen - map_end; -+ if (delta) -+ __munmap ((void *) map_end, delta); -+ } -+ -+ return map_start_aligned; -+} -+ - /* This implementation assumes (as does the corresponding implementation - of _dl_unmap_segments, in dl-unmap-segments.h) that shared objects - are always laid out with all segments contiguous (or with gaps -@@ -53,10 +98,7 @@ _dl_map_segments (struct link_map *l, int fd, - - MAP_BASE_ADDR (l)); - - /* Remember which part of the address space this object uses. */ -- l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength, -- c->prot, -- MAP_COPY|MAP_FILE, -- fd, c->mapoff); -+ l->l_map_start = _dl_map_segment (c, mappref, maplength, fd); - if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED)) - return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; - --- -2.18.4 - diff --git a/glibc-rh1159809-1.patch b/glibc-rh1159809-1.patch new file mode 100644 index 0000000..fb15043 --- /dev/null +++ b/glibc-rh1159809-1.patch @@ -0,0 +1,2024 @@ +commit e6fd79f3795d46dfb583e124be49fc063bc3d58b +Author: Chung-Lin Tang +Date: Thu Oct 21 21:41:21 2021 +0800 + + elf: Testing infrastructure for ld.so DSO sorting (BZ #17645) + + This is the first of a 2-part patch set that fixes slow DSO sorting behavior in + the dynamic loader, as reported in BZ #17645. In order to facilitate such a + large modification to the dynamic loader, this first patch implements a testing + framework for validating shared object sorting behavior, to enable comparison + between old/new sorting algorithms, and any later enhancements. + + This testing infrastructure consists of a Python script + scripts/dso-ordering-test.py' which takes in a description language, consisting + of strings that describe a set of link dependency relations between DSOs, and + generates testcase programs and Makefile fragments to automatically test the + described situation, for example: + + a->b->c->d # four objects linked one after another + + a->[bc]->d;b->c # a depends on b and c, which both depend on d, + # b depends on c (b,c linked to object a in fixed order) + + a->b->c;{+a;%a;-a} # a, b, c serially dependent, main program uses + # dlopen/dlsym/dlclose on object a + + a->b->c;{}!->[abc] # a, b, c serially dependent; multiple tests generated + # to test all permutations of a, b, c ordering linked + # to main program + + (Above is just a short description of what the script can do, more + documentation is in the script comments.) + + Two files containing several new tests, elf/dso-sort-tests-[12].def are added, + including test scenarios for BZ #15311 and Redhat issue #1162810 [1]. + + Due to the nature of dynamic loader tests, where the sorting behavior and test + output occurs before/after main(), generating testcases to use + support/test-driver.c does not suffice to control meaningful timeout for ld.so. + Therefore a new utility program 'support/test-run-command', based on + test-driver.c/support_test_main.c has been added. This does the same testcase + control, but for a program specified through a command-line rather than at the + source code level. This utility is used to run the dynamic loader testcases + generated by dso-ordering-test.py. + + [1] https://bugzilla.redhat.com/show_bug.cgi?id=1162810 + + Signed-off-by: Chung-Lin Tang + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index 1fdf40cbd49e233e..e92f62f279566684 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -986,6 +986,21 @@ tests-special += \ + # tests-special + endif + ++# DSO sorting tests: ++# The dso-ordering-test.py script generates testcase source files in $(objpfx), ++# creating a $(objpfx)-dir for each testcase, and creates a ++# Makefile fragment to be included. ++define include_dsosort_tests ++$(objpfx)$(1).generated-makefile: $(1) ++ $(PYTHON) $(..)scripts/dso-ordering-test.py \ ++ --description-file $$< --objpfx $(objpfx) --output-makefile $$@ ++include $(objpfx)$(1).generated-makefile ++endef ++ ++# Generate from each testcase description file ++$(eval $(call include_dsosort_tests,dso-sort-tests-1.def)) ++$(eval $(call include_dsosort_tests,dso-sort-tests-2.def)) ++ + check-abi: $(objpfx)check-abi-ld.out + tests-special += $(objpfx)check-abi-ld.out + update-abi: update-abi-ld +diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def +new file mode 100644 +index 0000000000000000..873ddf55d91155c6 +--- /dev/null ++++ b/elf/dso-sort-tests-1.def +@@ -0,0 +1,66 @@ ++# DSO sorting test descriptions. ++# This file is to be processed by ../scripts/dso-ordering-test.py, see usage ++# in elf/Makefile for how it is executed. ++ ++# We test both dynamic loader sorting algorithms ++tunable_option: glibc.rtld.dynamic_sort=1 ++tunable_option: glibc.rtld.dynamic_sort=2 ++ ++# Sequence of single dependencies with no cycles. ++tst-dso-ordering1: a->b->c ++output: c>b>a>{}b->[cd]->e ++output: e>d>c>b>a>{}[bc]->[def]->[gh]->i ++output: i>h>g>f>e>d>c>b>a>{}b->[de];a->c->d->e ++output: e>d>c>b>a>{}c cross link is respected correctly ++tst-dso-ordering5: a!->[bc]->d;b->c ++output: d>c>b>a>{}[bcde]->f ++output: f>e>d>c>b>a>{}[bc];b->[cde];e->f ++output: f>e>d>c>b>a>{}b->c=>a;{}->[ba] ++output: c>b>a>{}b->c->d->e;{}!->[abcde] ++output: e>d>c>b>a>{}a->b->c;soname({})=c ++output: b>a>{}b->c->d order). ++# The older dynamic_sort=1 algorithm does not achieve this, while the DFS-based ++# dynamic_sort=2 algorithm does, although it is still arguable whether going ++# beyond spec to do this is the right thing to do. ++# The below expected outputs are what the two algorithms currently produce ++# respectively, for regression testing purposes. ++tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c ++xfail_output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[A101 ++{}->* ++A101->(B101 B163 B122 B181) ++A102->(B102 B140 B199 B158) ++A103->(B103 B117 B176 B135) ++A104->(B104 B194 B153 B112) ++A105->(B105 B171 B130 B189) ++A106->(B106 B148 B107 B166) ++A107->(B107 B125 B184 B143) ++A108->(B108 B102 B161 B120) ++A109->(B109 B179 B138 B197) ++A110->(B110 B156 B115 B174) ++A111->(B111 B133 B192 B151) ++A112->(B112 B110 B169 B128) ++A113->(B113 B187 B146 B105) ++A114->(B114 B164 B123 B182) ++A115->(B115 B141 B200 B159) ++A116->(B116 B118 B177 B136) ++A117->(B117 B195 B154 B113) ++A118->(B118 B172 B131 B190) ++A119->(B119 B149 B108 B167) ++A120->(B120 B126 B185 B144) ++A121->(B121 B103 B162) ++A122->(B122 B180 B139 B198) ++A123->(B123 B157 B116 B175) ++A124->(B124 B134 B193 B152) ++A125->(B125 B111 B170 B129) ++A126->(B126 B188 B147 B106) ++A127->(B127 B165 B124 B183) ++A128->(B128 B142 B101 B160) ++A129->(B129 B119 B178 B137) ++A130->(B130 B196 B155 B114) ++A131->(B131 B173 B132 B191) ++A132->(B132 B150 B109 B168) ++A133->(B133 B127 B186 B145) ++A134->(B134 B104 B163 B122) ++A135->(B135 B181 B140 B199) ++A136->(B136 B158 B117 B176) ++A137->(B137 B135 B194 B153) ++A138->(B138 B112 B171 B130) ++A139->(B139 B189 B148 B107) ++A140->(B140 B166 B125 B184) ++A141->(B141 B143 B102 B161) ++A142->(B142 B120 B179 B138) ++A143->(B143 B197 B156 B115) ++A144->(B144 B174 B133 B192) ++A145->(B145 B151 B110 B169) ++A146->(B146 B128 B187) ++A147->(B147 B105 B164 B123) ++A148->(B148 B182 B141 B200) ++A149->(B149 B159 B118 B177) ++A150->(B150 B136 B195 B154) ++A151->(B151 B113 B172 B131) ++A152->(B152 B190 B149 B108) ++A153->(B153 B167 B126 B185) ++A154->(B154 B144 B103 B162) ++A155->(B155 B121 B180 B139) ++A156->(B156 B198 B157 B116) ++A157->(B157 B175 B134 B193) ++A158->(B158 B152 B111 B170) ++A159->(B159 B129 B188 B147) ++A160->(B160 B106 B165 B124) ++A161->(B161 B183 B142 B101) ++A162->(B162 B160 B119 B178) ++A163->(B163 B137 B196 B155) ++A164->(B164 B114 B173 B132) ++A165->(B165 B191 B150 B109) ++A166->(B166 B168 B127 B186) ++A167->(B167 B145 B104 B163) ++A168->(B168 B122 B181 B140) ++A169->(B169 B199 B158 B117) ++A170->(B170 B176 B135 B194) ++A171->(B171 B153 B112) ++A172->(B172 B130 B189 B148) ++A173->(B173 B107 B166 B125) ++A174->(B174 B184 B143 B102) ++A175->(B175 B161 B120 B179) ++A176->(B176 B138 B197 B156) ++A177->(B177 B115 B174 B133) ++A178->(B178 B192 B151 B110) ++A179->(B179 B169 B128 B187) ++A180->(B180 B146 B105 B164) ++A181->(B181 B123 B182 B141) ++A182->(B182 B200 B159 B118) ++A183->(B183 B177 B136 B195) ++A184->(B184 B154 B113 B172) ++A185->(B185 B131 B190 B149) ++A186->(B186 B108 B167 B126) ++A187->(B187 B185 B144 B103) ++A188->(B188 B162 B121 B180) ++A189->(B189 B139 B198 B157) ++A190->(B190 B116 B175 B134) ++A191->(B191 B193 B152 B111) ++A192->(B192 B170 B129 B188) ++A193->(B193 B147 B106 B165) ++A194->(B194 B124 B183 B142) ++A195->(B195 B101 B160 B119) ++A196->(B196 B178 B137) ++A197->(B197 B155 B114 B173) ++A198->(B198 B132 B191 B150) ++A199->(B199 B109 B168 B127) ++A200->(B200 B186 B145 B104) ++B101->(C101 C164 C123 C182) ++B102->(C102 C141 C200 C159) ++B103->(C103 C118 C177 C136) ++B104->(C104 C195 C154 C113) ++B105->(C105 C172 C131 C190) ++B106->(C106 C149 C108 C167) ++B107->(C107 C126 C185 C144) ++B108->(C108 C103 C162 C121) ++B109->(C109 C180 C139 C198) ++B110->(C110 C157 C116 C175) ++B111->(C111 C134 C193 C152) ++B112->(C112 C111 C170 C129) ++B113->(C113 C188 C147 C106) ++B114->(C114 C165 C124 C183) ++B115->(C115 C142 C101 C160) ++B116->(C116 C119 C178 C137) ++B117->(C117 C196 C155 C114) ++B118->(C118 C173 C132 C191) ++B119->(C119 C150 C109 C168) ++B120->(C120 C127 C186 C145) ++B121->(C121 C104 C163 C122) ++B122->(C122 C181 C140 C199) ++B123->(C123 C158 C117 C176) ++B124->(C124 C135 C194 C153) ++B125->(C125 C112 C171 C130) ++B126->(C126 C189 C148 C107) ++B127->(C127 C166 C125 C184) ++B128->(C128 C143 C102 C161) ++B129->(C129 C120 C179 C138) ++B130->(C130 C197 C156 C115) ++B131->(C131 C174 C133 C192) ++B132->(C132 C151 C110 C169) ++B133->(C133 C128 C187 C146) ++B134->(C134 C105 C164 C123) ++B135->(C135 C182 C141 C200) ++B136->(C136 C159 C118 C177) ++B137->(C137 C136 C195 C154) ++B138->(C138 C113 C172 C131) ++B139->(C139 C190 C149 C108) ++B140->(C140 C167 C126 C185) ++B141->(C141 C144 C103 C162) ++B142->(C142 C121 C180 C139) ++B143->(C143 C198 C157 C116) ++B144->(C144 C175 C134 C193) ++B145->(C145 C152 C111 C170) ++B146->(C146 C129 C188 C147) ++B147->(C147 C106 C165 C124) ++B148->(C148 C183 C142 C101) ++B149->(C149 C160 C119 C178) ++B150->(C150 C137 C196 C155) ++B151->(C151 C114 C173 C132) ++B152->(C152 C191 C150 C109) ++B153->(C153 C168 C127 C186) ++B154->(C154 C145 C104 C163) ++B155->(C155 C122 C181 C140) ++B156->(C156 C199 C158 C117) ++B157->(C157 C176 C135 C194) ++B158->(C158 C153 C112 C171) ++B159->(C159 C130 C189 C148) ++B160->(C160 C107 C166 C125) ++B161->(C161 C184 C143 C102) ++B162->(C162 C161 C120 C179) ++B163->(C163 C138 C197 C156) ++B164->(C164 C115 C174 C133) ++B165->(C165 C192 C151 C110) ++B166->(C166 C169 C128 C187) ++B167->(C167 C146 C105 C164) ++B168->(C168 C123 C182 C141) ++B169->(C169 C200 C159 C118) ++B170->(C170 C177 C136 C195) ++B171->(C171 C154 C113 C172) ++B172->(C172 C131 C190 C149) ++B173->(C173 C108 C167 C126) ++B174->(C174 C185 C144 C103) ++B175->(C175 C162 C121 C180) ++B176->(C176 C139 C198 C157) ++B177->(C177 C116 C175 C134) ++B178->(C178 C193 C152 C111) ++B179->(C179 C170 C129 C188) ++B180->(C180 C147 C106 C165) ++B181->(C181 C124 C183 C142) ++B182->(C182 C101 C160 C119) ++B183->(C183 C178 C137 C196) ++B184->(C184 C155 C114 C173) ++B185->(C185 C132 C191 C150) ++B186->(C186 C109 C168 C127) ++B187->(C187 C186 C145 C104) ++B188->(C188 C163 C122 C181) ++B189->(C189 C140 C199 C158) ++B190->(C190 C117 C176 C135) ++B191->(C191 C194 C153 C112) ++B192->(C192 C171 C130 C189) ++B193->(C193 C148 C107 C166) ++B194->(C194 C125 C184 C143) ++B195->(C195 C102 C161 C120) ++B196->(C196 C179 C138 C197) ++B197->(C197 C156 C115 C174) ++B198->(C198 C133 C192 C151) ++B199->(C199 C110 C169 C128) ++B200->(C200 C187 C146 C105) ++C101->(A165 A124) ++C102->(A183 A142) ++C103->(A101 A160) ++C104->(A119 A178) ++C105->(A137 A196) ++C106->(A155 A114) ++C107->(A173 A132) ++C108->(A191 A150) ++C109->(A109 A168) ++C110->(A127 A186) ++C111->(A145 A104) ++C112->(A163 A122) ++C113->(A181 A140) ++C114->(A199 A158) ++C115->(A117 A176) ++C116->(A135 A194) ++C117->(A153 A112) ++C118->(A171 A130) ++C119->(A189 A148) ++C120->(A107 A166) ++C121->(A125 A184) ++C122->(A143 A102) ++C123->(A161 A120) ++C124->(A179 A138) ++C125->(A197 A156) ++C126->(A115 A174) ++C127->(A133 A192) ++C128->(A151 A110) ++C129->(A169 A128) ++C130->(A187 A146) ++C131->(A105 A164) ++C132->(A123 A182) ++C133->(A141 A200) ++C134->(A159 A118) ++C135->(A177 A136) ++C136->(A195 A154) ++C137->(A113 A172) ++C138->(A131 A190) ++C139->(A149 A108) ++C140->(A167 A126) ++C141->(A185 A144) ++C142->(A103 A162) ++C143->(A121 A180) ++C144->(A139 A198) ++C145->(A157 A116) ++C146->(A175 A134) ++C147->(A193 A152) ++C148->(A111 A170) ++C149->(A129 A188) ++C150->(A147 A106) ++C151->(A165 A124) ++C152->(A183 A142) ++C153->(A101 A160) ++C154->(A119 A178) ++C155->(A137 A196) ++C156->(A155 A114) ++C157->(A173 A132) ++C158->(A191 A150) ++C159->(A109 A168) ++C160->(A127 A186) ++C161->(A145 A104) ++C162->(A163 A122) ++C163->(A181 A140) ++C164->(A199 A158) ++C165->(A117 A176) ++C166->(A135 A194) ++C167->(A153 A112) ++C168->(A171 A130) ++C169->(A189 A148) ++C170->(A107 A166) ++C171->(A125 A184) ++C172->(A143 A102) ++C173->(A161 A120) ++C174->(A179 A138) ++C175->(A197 A156) ++C176->(A115 A174) ++C177->(A133 A192) ++C178->(A151 A110) ++C179->(A169 A128) ++C180->(A187 A146) ++C181->(A105 A164) ++C182->(A123 A182) ++C183->(A141 A200) ++C184->(A159 A118) ++C185->(A177 A136) ++C186->(A195 A154) ++C187->(A113 A172) ++C188->(A131 A190) ++C189->(A149 A108) ++C190->(A167 A126) ++C191->(A185 A144) ++C192->(A103 A162) ++C193->(A121 A180) ++C194->(A139 A198) ++C195->(A157 A116) ++C196->(A175 A134) ++C197->(A193 A152) ++C198->(A111 A170) ++C199->(A129 A188) ++C200->(A147 A106) ++M11X11->(M13X14 M12X13 M12X12 M12X11) ++M11X12->(M13X25 M12X24 M12X23 M12X22) ++M11X13->(M13X21 M12X20 M12X19 M12X18) ++M11X14->(M13X17 M12X16 M12X15 M12X14) ++M11X15->(M13X13 M12X12 M12X11 M12X25) ++M11X16->(M13X24 M12X23 M12X22 M12X21) ++M11X17->(M13X20 M12X19 M12X18 M12X17) ++M11X18->(M13X16 M12X15 M12X14 M12X13) ++M11X19->(M13X12 M12X11 M12X25 M12X24) ++M11X20->(M13X23 M12X22 M12X21 M12X20) ++M11X21->(M13X19 M12X18 M12X17 M12X16) ++M11X22->(M13X15 M12X14 M12X13 M12X12) ++M11X23->(M13X11 M12X25 M12X24 M12X23) ++M11X24->(M13X22 M12X21 M12X20 M12X19) ++M11X25->(M13X18 M12X17 M12X16 M12X15) ++M12X11->(M14X14 M13X13 M13X12 M13X11) ++M12X12->(M14X25 M13X24 M13X23 M13X22) ++M12X13->(M14X21 M13X20 M13X19 M13X18) ++M12X14->(M14X17 M13X16 M13X15 M13X14) ++M12X15->(M14X13 M13X12 M13X11 M13X25) ++M12X16->(M14X24 M13X23 M13X22 M13X21) ++M12X17->(M14X20 M13X19 M13X18 M13X17) ++M12X18->(M14X16 M13X15 M13X14 M13X13) ++M12X19->(M14X12 M13X11 M13X25 M13X24) ++M12X20->(M14X23 M13X22 M13X21 M13X20) ++M12X21->(M14X19 M13X18 M13X17 M13X16) ++M12X22->(M14X15 M13X14 M13X13 M13X12) ++M12X23->(M14X11 M13X25 M13X24 M13X23) ++M12X24->(M14X22 M13X21 M13X20 M13X19) ++M12X25->(M14X18 M13X17 M13X16 M13X15) ++M13X11->(M15X14 M14X13 M14X12 M14X11) ++M13X12->(M15X25 M14X24 M14X23 M14X22) ++M13X13->(M15X21 M14X20 M14X19 M14X18) ++M13X14->(M15X17 M14X16 M14X15 M14X14) ++M13X15->(M15X13 M14X12 M14X11 M14X25) ++M13X16->(M15X24 M14X23 M14X22 M14X21) ++M13X17->(M15X20 M14X19 M14X18 M14X17) ++M13X18->(M15X16 M14X15 M14X14 M14X13) ++M13X19->(M15X12 M14X11 M14X25 M14X24) ++M13X20->(M15X23 M14X22 M14X21 M14X20) ++M13X21->(M15X19 M14X18 M14X17 M14X16) ++M13X22->(M15X15 M14X14 M14X13 M14X12) ++M13X23->(M15X11 M14X25 M14X24 M14X23) ++M13X24->(M15X22 M14X21 M14X20 M14X19) ++M13X25->(M15X18 M14X17 M14X16 M14X15) ++M14X11->(M16X14 M15X13 M15X12 M15X11) ++M14X12->(M16X25 M15X24 M15X23 M15X22) ++M14X13->(M16X21 M15X20 M15X19 M15X18) ++M14X14->(M16X17 M15X16 M15X15 M15X14) ++M14X15->(M16X13 M15X12 M15X11 M15X25) ++M14X16->(M16X24 M15X23 M15X22 M15X21) ++M14X17->(M16X20 M15X19 M15X18 M15X17) ++M14X18->(M16X16 M15X15 M15X14 M15X13) ++M14X19->(M16X12 M15X11 M15X25 M15X24) ++M14X20->(M16X23 M15X22 M15X21 M15X20) ++M14X21->(M16X19 M15X18 M15X17 M15X16) ++M14X22->(M16X15 M15X14 M15X13 M15X12) ++M14X23->(M16X11 M15X25 M15X24 M15X23) ++M14X24->(M16X22 M15X21 M15X20 M15X19) ++M14X25->(M16X18 M15X17 M15X16 M15X15) ++M15X11->(M17X14 M16X13 M16X12 M16X11) ++M15X12->(M17X25 M16X24 M16X23 M16X22) ++M15X13->(M17X21 M16X20 M16X19 M16X18) ++M15X14->(M17X17 M16X16 M16X15 M16X14) ++M15X15->(M17X13 M16X12 M16X11 M16X25) ++M15X16->(M17X24 M16X23 M16X22 M16X21) ++M15X17->(M17X20 M16X19 M16X18 M16X17) ++M15X18->(M17X16 M16X15 M16X14 M16X13) ++M15X19->(M17X12 M16X11 M16X25 M16X24) ++M15X20->(M17X23 M16X22 M16X21 M16X20) ++M15X21->(M17X19 M16X18 M16X17 M16X16) ++M15X22->(M17X15 M16X14 M16X13 M16X12) ++M15X23->(M17X11 M16X25 M16X24 M16X23) ++M15X24->(M17X22 M16X21 M16X20 M16X19) ++M15X25->(M17X18 M16X17 M16X16 M16X15) ++M16X11->(M18X14 M17X13 M17X12 M17X11) ++M16X12->(M18X25 M17X24 M17X23 M17X22) ++M16X13->(M18X21 M17X20 M17X19 M17X18) ++M16X14->(M18X17 M17X16 M17X15 M17X14) ++M16X15->(M18X13 M17X12 M17X11 M17X25) ++M16X16->(M18X24 M17X23 M17X22 M17X21) ++M16X17->(M18X20 M17X19 M17X18 M17X17) ++M16X18->(M18X16 M17X15 M17X14 M17X13) ++M16X19->(M18X12 M17X11 M17X25 M17X24) ++M16X20->(M18X23 M17X22 M17X21 M17X20) ++M16X21->(M18X19 M17X18 M17X17 M17X16) ++M16X22->(M18X15 M17X14 M17X13 M17X12) ++M16X23->(M18X11 M17X25 M17X24 M17X23) ++M16X24->(M18X22 M17X21 M17X20 M17X19) ++M16X25->(M18X18 M17X17 M17X16 M17X15) ++M17X11->(M19X14 M18X13 M18X12 M18X11) ++M17X12->(M19X25 M18X24 M18X23 M18X22) ++M17X13->(M19X21 M18X20 M18X19 M18X18) ++M17X14->(M19X17 M18X16 M18X15 M18X14) ++M17X15->(M19X13 M18X12 M18X11 M18X25) ++M17X16->(M19X24 M18X23 M18X22 M18X21) ++M17X17->(M19X20 M18X19 M18X18 M18X17) ++M17X18->(M19X16 M18X15 M18X14 M18X13) ++M17X19->(M19X12 M18X11 M18X25 M18X24) ++M17X20->(M19X23 M18X22 M18X21 M18X20) ++M17X21->(M19X19 M18X18 M18X17 M18X16) ++M17X22->(M19X15 M18X14 M18X13 M18X12) ++M17X23->(M19X11 M18X25 M18X24 M18X23) ++M17X24->(M19X22 M18X21 M18X20 M18X19) ++M17X25->(M19X18 M18X17 M18X16 M18X15) ++M18X11->(M20X14 M19X13 M19X12 M19X11) ++M18X12->(M20X25 M19X24 M19X23 M19X22) ++M18X13->(M20X21 M19X20 M19X19 M19X18) ++M18X14->(M20X17 M19X16 M19X15 M19X14) ++M18X15->(M20X13 M19X12 M19X11 M19X25) ++M18X16->(M20X24 M19X23 M19X22 M19X21) ++M18X17->(M20X20 M19X19 M19X18 M19X17) ++M18X18->(M20X16 M19X15 M19X14 M19X13) ++M18X19->(M20X12 M19X11 M19X25 M19X24) ++M18X20->(M20X23 M19X22 M19X21 M19X20) ++M18X21->(M20X19 M19X18 M19X17 M19X16) ++M18X22->(M20X15 M19X14 M19X13 M19X12) ++M18X23->(M20X11 M19X25 M19X24 M19X23) ++M18X24->(M20X22 M19X21 M19X20 M19X19) ++M18X25->(M20X18 M19X17 M19X16 M19X15) ++M19X11->(M21X14 M20X13 M20X12 M20X11) ++M19X12->(M21X25 M20X24 M20X23 M20X22) ++M19X13->(M21X21 M20X20 M20X19 M20X18) ++M19X14->(M21X17 M20X16 M20X15 M20X14) ++M19X15->(M21X13 M20X12 M20X11 M20X25) ++M19X16->(M21X24 M20X23 M20X22 M20X21) ++M19X17->(M21X20 M20X19 M20X18 M20X17) ++M19X18->(M21X16 M20X15 M20X14 M20X13) ++M19X19->(M21X12 M20X11 M20X25 M20X24) ++M19X20->(M21X23 M20X22 M20X21 M20X20) ++M19X21->(M21X19 M20X18 M20X17 M20X16) ++M19X22->(M21X15 M20X14 M20X13 M20X12) ++M19X23->(M21X11 M20X25 M20X24 M20X23) ++M19X24->(M21X22 M20X21 M20X20 M20X19) ++M19X25->(M21X18 M20X17 M20X16 M20X15) ++M20X11->(M22X14 M21X13 M21X12 M21X11) ++M20X12->(M22X25 M21X24 M21X23 M21X22) ++M20X13->(M22X21 M21X20 M21X19 M21X18) ++M20X14->(M22X17 M21X16 M21X15 M21X14) ++M20X15->(M22X13 M21X12 M21X11 M21X25) ++M20X16->(M22X24 M21X23 M21X22 M21X21) ++M20X17->(M22X20 M21X19 M21X18 M21X17) ++M20X18->(M22X16 M21X15 M21X14 M21X13) ++M20X19->(M22X12 M21X11 M21X25 M21X24) ++M20X20->(M22X23 M21X22 M21X21 M21X20) ++M20X21->(M22X19 M21X18 M21X17 M21X16) ++M20X22->(M22X15 M21X14 M21X13 M21X12) ++M20X23->(M22X11 M21X25 M21X24 M21X23) ++M20X24->(M22X22 M21X21 M21X20 M21X19) ++M20X25->(M22X18 M21X17 M21X16 M21X15) ++M21X11->(M23X15 M22X14 M22X13 M22X12) ++M21X12->(M11X11 M23X25 M22X24 M22X23 M22X22) ++M21X13->(M23X21 M22X20 M22X19 M22X18) ++M21X14->(M23X17 M22X16 M22X15 M22X14) ++M21X15->(M23X13 M22X12 M22X11 M22X25) ++M21X16->(M23X24 M22X23 M22X22 M22X21) ++M21X17->(M23X20 M22X19 M22X18 M22X17) ++M21X18->(M23X16 M22X15 M22X14 M22X13) ++M21X19->(M23X12 M22X11 M22X25 M22X24) ++M21X20->(M23X23 M22X22 M22X21 M22X20) ++M21X21->(M23X19 M22X18 M22X17 M22X16) ++M21X22->(M23X15 M22X14 M22X13 M22X12) ++M21X23->(M23X11 M22X25 M22X24 M22X23) ++M21X24->(M23X22 M22X21 M22X20 M22X19) ++M21X25->(M23X18 M22X17 M22X16 M22X15) ++M22X11->(M24X16 M23X15 M23X14 M23X13) ++M22X12->(M12X12 M24X11 M23X25 M23X24 M23X23) ++M22X13->(M24X22 M23X21 M23X20 M23X19) ++M22X14->(M24X18 M23X17 M23X16 M23X15) ++M22X15->(M24X14 M23X13 M23X12 M23X11) ++M22X16->(M24X25 M23X24 M23X23 M23X22) ++M22X17->(M24X21 M23X20 M23X19 M23X18) ++M22X18->(M24X17 M23X16 M23X15 M23X14) ++M22X19->(M24X13 M23X12 M23X11 M23X25) ++M22X20->(M24X24 M23X23 M23X22 M23X21) ++M22X21->(M24X20 M23X19 M23X18 M23X17) ++M22X22->(M24X16 M23X15 M23X14 M23X13) ++M22X23->(M24X12 M23X11 M23X25 M23X24) ++M22X24->(M24X23 M23X22 M23X21 M23X20) ++M22X25->(M24X19 M23X18 M23X17 M23X16) ++M23X11->(M25X17 M24X16 M24X15 M24X14) ++M23X12->(M13X13 M25X12 M24X11 M24X25 M24X24) ++M23X13->(M25X23 M24X22 M24X21 M24X20) ++M23X14->(M25X19 M24X18 M24X17 M24X16) ++M23X15->(M25X15 M24X14 M24X13 M24X12) ++M23X16->(M25X11 M24X25 M24X24 M24X23) ++M23X17->(M25X22 M24X21 M24X20 M24X19) ++M23X18->(M25X18 M24X17 M24X16 M24X15) ++M23X19->(M25X14 M24X13 M24X12 M24X11) ++M23X20->(M25X25 M24X24 M24X23 M24X22) ++M23X21->(M25X21 M24X20 M24X19 M24X18) ++M23X22->(M25X17 M24X16 M24X15 M24X14) ++M23X23->(M25X13 M24X12 M24X11 M24X25) ++M23X24->(M25X24 M24X23 M24X22 M24X21) ++M23X25->(M25X20 M24X19 M24X18 M24X17) ++M24X11->(M26X18 M25X17 M25X16 M25X15) ++M24X12->(M14X14 M26X13 M25X12 M25X11 M25X25) ++M24X13->(M26X24 M25X23 M25X22 M25X21) ++M24X14->(M26X20 M25X19 M25X18 M25X17) ++M24X15->(M26X16 M25X15 M25X14 M25X13) ++M24X16->(M26X12 M25X11 M25X25 M25X24) ++M24X17->(M26X23 M25X22 M25X21 M25X20) ++M24X18->(M26X19 M25X18 M25X17 M25X16) ++M24X19->(M26X15 M25X14 M25X13 M25X12) ++M24X20->(M26X11 M25X25 M25X24 M25X23) ++M24X21->(M26X22 M25X21 M25X20 M25X19) ++M24X22->(M26X18 M25X17 M25X16 M25X15) ++M24X23->(M26X14 M25X13 M25X12 M25X11) ++M24X24->(M26X25 M25X24 M25X23 M25X22) ++M24X25->(M26X21 M25X20 M25X19 M25X18) ++M25X11->(M27X19 M26X18 M26X17 M26X16) ++M25X12->(M15X15 M27X14 M26X13 M26X12 M26X11) ++M25X13->(M27X25 M26X24 M26X23 M26X22) ++M25X14->(M27X21 M26X20 M26X19 M26X18) ++M25X15->(M27X17 M26X16 M26X15 M26X14) ++M25X16->(M27X13 M26X12 M26X11 M26X25) ++M25X17->(M27X24 M26X23 M26X22 M26X21) ++M25X18->(M27X20 M26X19 M26X18 M26X17) ++M25X19->(M27X16 M26X15 M26X14 M26X13) ++M25X20->(M27X12 M26X11 M26X25 M26X24) ++M25X21->(M27X23 M26X22 M26X21 M26X20) ++M25X22->(M27X19 M26X18 M26X17 M26X16) ++M25X23->(M27X15 M26X14 M26X13 M26X12) ++M25X24->(M27X11 M26X25 M26X24 M26X23) ++M25X25->(M27X22 M26X21 M26X20 M26X19) ++M26X11->(M28X20 M27X19 M27X18 M27X17) ++M26X12->(M16X16 M28X15 M27X14 M27X13 M27X12) ++M26X13->(M28X11 M27X25 M27X24 M27X23) ++M26X14->(M28X22 M27X21 M27X20 M27X19) ++M26X15->(M28X18 M27X17 M27X16 M27X15) ++M26X16->(M28X14 M27X13 M27X12 M27X11) ++M26X17->(M28X25 M27X24 M27X23 M27X22) ++M26X18->(M28X21 M27X20 M27X19 M27X18) ++M26X19->(M28X17 M27X16 M27X15 M27X14) ++M26X20->(M28X13 M27X12 M27X11 M27X25) ++M26X21->(M28X24 M27X23 M27X22 M27X21) ++M26X22->(M28X20 M27X19 M27X18 M27X17) ++M26X23->(M28X16 M27X15 M27X14 M27X13) ++M26X24->(M28X12 M27X11 M27X25 M27X24) ++M26X25->(M28X23 M27X22 M27X21 M27X20) ++M27X11->(M29X21 M28X20 M28X19 M28X18) ++M27X12->(M17X17 M29X16 M28X15 M28X14 M28X13) ++M27X13->(M29X12 M28X11 M28X25 M28X24) ++M27X14->(M29X23 M28X22 M28X21 M28X20) ++M27X15->(M29X19 M28X18 M28X17 M28X16) ++M27X16->(M29X15 M28X14 M28X13 M28X12) ++M27X17->(M29X11 M28X25 M28X24 M28X23) ++M27X18->(M29X22 M28X21 M28X20 M28X19) ++M27X19->(M29X18 M28X17 M28X16 M28X15) ++M27X20->(M29X14 M28X13 M28X12 M28X11) ++M27X21->(M29X25 M28X24 M28X23 M28X22) ++M27X22->(M29X21 M28X20 M28X19 M28X18) ++M27X23->(M29X17 M28X16 M28X15 M28X14) ++M27X24->(M29X13 M28X12 M28X11 M28X25) ++M27X25->(M29X24 M28X23 M28X22 M28X21) ++M28X11->(M30X22 M29X21 M29X20 M29X19) ++M28X12->(M18X18 M30X17 M29X16 M29X15 M29X14) ++M28X13->(M30X13 M29X12 M29X11 M29X25) ++M28X14->(M30X24 M29X23 M29X22 M29X21) ++M28X15->(M30X20 M29X19 M29X18 M29X17) ++M28X16->(M30X16 M29X15 M29X14 M29X13) ++M28X17->(M30X12 M29X11 M29X25 M29X24) ++M28X18->(M30X23 M29X22 M29X21 M29X20) ++M28X19->(M30X19 M29X18 M29X17 M29X16) ++M28X20->(M30X15 M29X14 M29X13 M29X12) ++M28X21->(M30X11 M29X25 M29X24 M29X23) ++M28X22->(M30X22 M29X21 M29X20 M29X19) ++M28X23->(M30X18 M29X17 M29X16 M29X15) ++M28X24->(M30X14 M29X13 M29X12 M29X11) ++M28X25->(M30X25 M29X24 M29X23 M29X22) ++M29X11->(M30X22 M30X21 M30X20) ++M29X12->(M30X17 M30X16 M30X15) ++M29X13->(M30X13 M30X12 M30X11) ++M29X14->(M30X24 M30X23 M30X22) ++M29X15->(M30X20 M30X19 M30X18) ++M29X16->(M30X16 M30X15 M30X14) ++M29X17->(M30X12 M30X11 M30X25) ++M29X18->(M30X23 M30X22 M30X21) ++M29X19->(M30X19 M30X18 M30X17) ++M29X20->(M30X15 M30X14 M30X13) ++M29X21->(M30X11 M30X25 M30X24) ++M29X22->(M30X22 M30X21 M30X20) ++M29X23->(M30X18 M30X17 M30X16) ++M29X24->(M30X14 M30X13 M30X12) ++M29X25->(M30X25 M30X24 M30X23) ++M30X11 ++M30X12 ++M30X13 ++M30X14 ++M30X15 ++M30X16 ++M30X17 ++M30X18 ++M30X19 ++M30X20 ++M30X21 ++M30X22 ++M30X23 ++M30X24 ++M30X25 ++xfail_output(glibc.rtld.dynamic_sort=1): M30X19>M30X15>M30X16>M30X11>M30X12>M30X17>M30X13>M30X14>M29X20>M30X23>M30X24>M30X20>M30X18>M29X15>M29X12>M30X22>M30X21>M29X22>M30X25>M29X19>M29X23>M29X16>M29X24>M29X13>M29X17>M29X18>M28X19>M29X21>M29X25>M29X14>M28X20>M28X15>M28X16>M28X21>M27X18>M29X11>M28X17>M28X11>M28X22>M27X14>M28X18>M27X15>M28X13>M27X11>M28X23>M27X25>M28X14>M28X25>M27X23>M27X22>M28X24>M27X21>M27X13>M27X19>M27X17>M26X11>M26X23>M26X21>M26X22>M26X20>M26X16>M25X21>M17X22>M15X15>M20X14>M20X16>M18X18>M28X12>M27X24>M25X17>M27X20>M26X18>M26X17>M27X16>M26X19>M25X18>M26X24>M25X20>M24X17>M23X18>M25X13>M26X13>M17X23>M16X16>M26X12>M25X12>M26X15>M24X19>M25X23>M25X24>M25X25>M24X20>M25X19>M24X21>M23X17>M22X21>M24X14>M23X22>M24X24>M22X20>M24X13>M25X11>M24X12>M25X15>M23X15>M25X16>M24X22>M23X13>M24X18>M23X14>M22X22>M21X20>M24X25>M23X16>M22X25>M21X19>M22X14>M23X11>M22X15>M21X18>M22X19>M21X17>M20X17>M19X17>M21X24>M21X12>M20X22>M19X16>M18X25>M19X21>M19X20>M18X24>M20X12>M19X11>M23X20>M22X24>M22X16>M21X21>M25X14>M23X19>M23X24>M20X24>M19X12>M18X15>M17X14>M16X18>M14X25>M16X22>M16X20>M17X17>M22X12>M21X11>M20X15>M18X22>M19X24>M19X18>M18X21>M17X16>M17X18>M16X21>M15X20>M19X22>M18X20>M18X11>M17X19>M16X17>M15X21>M16X14>M16X13>M15X22>M14X20>M17X25>M16X19>M14X21>M13X24>M12X12>M16X24>M15X23>M14X16>M16X15>M15X25>M15X11>M15X12>M14X15>M13X14>M14X22>M13X20>M12X13>M11X11>M22X23>M21X15>M21X16>M20X21>M20X20>M18X17>M19X25>M18X23>M21X13>M15X17>M15X18>M18X19>M17X24>M16X12>M17X13>M20X25>M19X23>M15X19>M14X13>M13X18>M15X13>M17X12>M16X11>M18X13>M18X12>M14X11>M14X24>M13X19>M15X14>M17X20>M20X11>M20X13>M21X14>M15X24>M14X12>M13X22>M14X23>M13X23>M14X19>M17X15>M16X25>M17X11>M18X14>M19X19>M21X25>M13X12>M13X11>M14X18>M13X13>M12X11>M15X16>M14X14>M27X12>M17X21>M20X23>M22X13>M21X22>M24X16>M24X15>M26X25>M23X25>M26X14>M23X12>M22X18>M24X11>M16X23>M19X14>M19X13>M21X23>M22X17>M23X23>M23X21>M25X22>M18X16>M19X15>M20X18>M20X19>M22X11>M24X23>C156>C118>C143>C137>C147>C106>C168>C113>C163>C155>C105>C146>C187>A150>C139>C180>C164>C193>C157>A191>C158>B188>A159>C184>C121>C154>B171>A105>C131>C104>B104>C161>C111>B145>C160>B155>A163>C112>C142>B148>C133>B198>A198>A115>C114>B157>A156>C175>B144>A120>C173>B184>A174>C126>B107>A139>C194>B194>A194>C116>B116>C166>B160>B110>A110>C128>B128>A128>C179>B162>A154>C186>B187>A179>C124>B181>A101>C153>B158>A136>C135>C176>A192>B133>A133>C177>B177>A177>C185>C103>B141>A141>C183>A162>C192>C129>B179>C144>B124>B183>C127>B127>A127>B108>A112>B153>A153>C167>B167>A186>A122>C162>A144>B149>C174>B131>A185>C141>B106>A126>A167>C140>B122>A170>C198>B143>C117>C123>B123>A147>A106>C200>B169>C191>B175>A123>B118>A182>C132>B151>A145>A104>A109>C159>C150>B119>A119>A178>B164>B114>A164>C181>A102>C122>B134>A157>A116>C195>B191>B111>C172>B172>A118>B129>A129>C149>A107>C170>B197>A197>A173>B168>A132>C107>B165>A160>A131>C188>A168>B109>C178>A189>A148>C119>C190>C120>B166>B176>C108>B135>B139>A103>B178>A169>B132>C125>C138>B163>A111>B170>C110>A165>C151>C169>C199>A138>C182>A135>B101>B142>C101>C148>B193>B152>A158>A199>C136>B137>A161>B120>A108>A149>A125>B113>A184>C171>A134>A175>A124>B150>B161>B102>A146>A187>C130>B192>B200>A200>A142>A183>C102>B105>B156>A176>C165>B147>A137>A196>B190>A190>B125>C134>C189>B126>B186>A166>B136>B195>A195>B154>B138>B112>B173>A117>B159>B182>A181>A140>C145>B117>A152>A193>C197>B130>A172>A113>A151>B115>A143>B140>B185>B103>A121>A180>A130>A171>B199>C196>B146>B180>C115>B174>B121>A188>B196>B189>C152>C109>A155>A114>M14X17>M13X15>M13X16>M13X17>M12X17>M12X21>M12X25>M12X14>M13X25>M12X15>M13X21>M12X16>M12X18>M12X19>M12X20>M12X22>M12X23>M12X24>M11X25>M11X24>M11X23>M11X22>M11X21>M11X20>M11X19>M11X18>M11X17>M11X16>M11X15>M11X14>M11X13>M11X12>{}M30X15>M30X16>M30X11>M30X12>M30X17>M30X13>M30X14>M29X20>M30X23>M30X24>M30X20>M30X18>M29X15>M29X12>M30X22>M30X21>M29X22>M30X25>M29X19>M29X23>M29X16>M29X24>M29X13>M29X17>M29X18>M28X19>M29X21>M29X25>M29X14>M28X20>M28X15>M28X16>M28X21>M27X18>M29X11>M28X17>M28X11>M28X22>M28X24>M28X23>M27X21>M28X13>M27X20>M27X19>M26X14>M27X25>M28X18>M27X11>M28X25>M27X24>M26X24>M27X15>M27X14>M27X13>M26X23>M27X17>M26X22>M25X13>M28X14>M27X16>M26X19>M26X18>M27X23>M27X22>M26X17>M25X18>M26X21>M25X17>M26X20>M26X15>M26X13>M25X19>M24X14>M25X23>M26X11>M26X25>M25X16>M25X15>M24X22>M25X21>M25X20>M24X21>M25X25>M25X24>M24X20>M23X13>M22X15>M25X14>M24X19>M23X17>M24X25>M23X24>M24X13>M23X15>M24X18>M23X14>M22X11>M24X15>M23X22>M24X11>M23X19>M22X21>M24X24>M23X21>M22X20>M23X25>M22X19>M21X24>M20X23>M22X22>M25X11>M23X16>M22X18>M23X20>M22X17>M21X21>M21X20>M20X24>M22X14>M22X13>M21X11>M21X17>M22X23>M21X16>M20X25>M19X23>M18X16>M21X22>M20X20>M20X19>M21X13>M20X18>M19X13>M21X18>M20X21>M19X24>M18X12>M20X14>M20X13>M22X25>M20X12>M20X15>M19X14>M18X22>M19X18>M20X17>M19X17>M19X16>M18X21>M17X20>M19X19>M18X13>M17X11>M18X17>M19X25>M18X15>M17X25>M18X19>M17X24>M16X19>M15X17>M17X21>M16X24>M18X23>M17X16>M16X25>M19X15>M18X25>M17X23>M16X23>M15X23>M18X14>M17X14>M16X14>M17X18>M16X13>M17X22>M16X12>M15X22>M14X16>M17X12>M16X22>M15X12>M16X11>M15X11>M16X15>M15X25>M14X15>M13X14>M15X18>M16X21>M15X16>M14X21>M15X14>M16X20>M15X13>M14X22>M15X20>M14X20>M13X20>M14X11>M15X19>M14X24>M13X19>M14X13>M13X18>M12X13>M15X24>M14X23>M13X12>M14X12>M13X11>M12X11>M11X11>M21X12>M20X11>M19X11>M18X11>M17X15>M16X18>M14X25>M14X19>M13X24>M13X23>M13X22>M12X12>M22X12>M21X15>M19X22>M18X20>M16X17>M14X14>M24X12>M23X23>M22X16>M21X14>M20X22>M18X24>M16X16>M26X12>M24X16>M23X11>M21X23>M19X20>M17X17>M27X12>M26X16>M25X22>M24X17>M23X18>M21X25>M19X12>M17X19>M15X21>M14X18>M13X13>M23X12>M21X19>M19X21>M17X13>M15X15>M25X12>M24X23>M22X24>M20X16>M18X18>M28X12>A150>C158>B112>A112>C167>B146>A146>C180>B180>A180>C143>B143>A115>C126>B126>A126>C190>B190>A190>C138>B138>A138>C174>B174>A102>C122>B122>A122>C162>B162>A162>C142>B142>A142>C102>B102>A174>C176>B176>A176>C115>B115>A143>C172>B172>A172>C187>B187>A187>C130>B130>A130>C118>B118>A118>C184>B184>A184>C171>B171>A171>C168>B182>A182>C182>B168>A168>C109>B109>A109>C159>B159>A159>C134>B134>A134>C146>B167>A167>C140>B140>A140>C163>B163>A163>C112>B158>A158>C164>B164>A164>C131>B131>A131>C188>B188>A188>C199>B199>A199>C114>B114>A114>C106>B106>A106>C200>B200>A200>C183>B183>A183>C152>B152>A152>C147>B147>A147>C150>B150>A198>C144>B144>A144>C191>B191>A191>C108>B108>A108>C139>B139>A139>C194>B194>A194>C166>B166>A166>C120>B120>A120>C123>B123>A123>C132>B132>A132>C107>B107>A107>C170>B170>A170>C198>B198>A156>C125>B125>A125>C121>B121>A121>C193>B193>A193>C197>B197>A197>C175>B175>A175>C196>B196>A196>C105>B105>A105>C181>B181>A181>C113>B113>A113>C137>B137>A137>C155>B155>A155>C156>B156>A110>C128>B128>A128>C179>B179>A179>C124>B124>A124>C151>B151>A151>C178>B178>A178>C104>B104>A104>C111>B111>A111>C148>B148>A148>C169>B169>A169>C129>B129>A129>C149>B149>A149>C189>B189>A189>C119>B119>A119>C154>B154>A154>C136>B136>A136>C135>B135>A135>C116>B116>A116>C145>B145>A145>C161>B161>A161>C173>B173>A173>C157>B157>A157>C195>B195>A195>C186>B186>A186>C160>B160>A160>C153>B153>A153>C117>B117>A117>C165>B165>A165>C101>B101>A101>C103>B103>A103>C192>B192>A192>C177>B177>A177>C185>B185>A185>C141>B141>A141>C133>B133>A133>C127>B127>A127>C110>B110>M14X17>M13X15>M13X16>M13X17>M12X17>M12X21>M12X25>M12X14>M13X25>M12X15>M13X21>M12X16>M12X18>M12X19>M12X20>M12X22>M12X23>M12X24>M11X25>M11X24>M11X23>M11X22>M11X21>M11X20>M11X19>M11X18>M11X17>M11X16>M11X15>M11X14>M11X13>M11X12>{}. ++ ++"""Generate testcase files and Makefile fragments for DSO sorting test ++ ++This script takes a small description string language, and generates ++testcases for displaying the ELF dynamic linker's dependency sorting ++behavior, allowing verification. ++ ++Testcase descriptions are semicolon-separated description strings, and ++this tool generates a testcase from the description, including main program, ++associated modules, and Makefile fragments for including into elf/Makefile. ++ ++This allows automation of what otherwise would be very laborous manual ++construction of complex dependency cases, however it must be noted that this ++is only a tool to speed up testcase construction, and thus the generation ++features are largely mechanical in nature; inconsistencies or errors may occur ++if the input description was itself erroneous or have unforeseen interactions. ++ ++The format of the input test description files are: ++ ++ # Each test description has a name, lines of description, ++ # and an expected output specification. Comments use '#'. ++ testname1: ++ output: ++ ++ # Tests can be marked to be XFAIL by using 'xfail_output' instead ++ testname2: ++ xfail_output: ++ ++ # A default set of GLIBC_TUNABLES tunables can be specified, for which ++ # all following tests will run multiple times, once for each of the ++ # GLIBC_TUNABLES=... strings set by the 'tunable_option' command. ++ tunable_option: ++ tunable_option: ++ ++ # Test descriptions can use multiple lines, which will all be merged ++ # together, so order is not important. ++ testname3: ++ ++ ++ ... ++ output: ++ ++ # 'testname3' will be run and compared two times, for both ++ # GLIBC_TUNABLES= and ++ # GLIBC_TUNABLES=. This can be cleared and reset by the ++ # 'clear_tunables' command: ++ clear_tunables ++ ++ # Multiple expected outputs can also be specified, with an associated ++ # tunable option in (), which multiple tests will be run with each ++ # GLIBC_TUNABLES=... option tried. ++ testname4: ++ ++ ... ++ output(): ++ output(): ++ # Individual tunable output cases can be XFAILed, though note that ++ # this will have the effect of XFAILing the entire 'testname4' test ++ # in the final top-level tests.sum summary. ++ xfail_output(): ++ ++ # When multiple outputs (with specific tunable strings) are specified, ++ # these take priority over any active 'tunable_option' settings. ++ ++ # When a test is meant to be placed under 'xtests' (not run under ++ # "make check", but only when "make xtests" is used), the testcase name can be ++ # declared using 'xtest()': ++ ... ++ xtest(test-too-big1): ++ output: ++ ... ++ ++ # Do note that under current elf/Makefile organization, for such a xtest case, ++ # while the test execution is only run under 'make xtests', the associated ++ # DSOs are always built even under 'make check'. ++ ++On the description language used, an example description line string: ++ ++ a->b!->[cdef];c=>g=>h;{+c;%c;-c}->a ++ ++Each identifier represents a shared object module, currently sequences of ++letters/digits are allowed, case-sensitive. ++ ++All such shared objects have a constructor/destructor generated for them ++that emits its name followed by a '>' for constructors, and '<' followed by ++its name for destructors, e.g. if the name is 'obj1', then "obj1>" and " operator specifies a link time dependency, these can be chained for ++convenience (e.g. a->b->c->d). ++ ++The => operator creates a call-reference, e.g. for a=>b, an fn_a() function ++is created inside module 'a', which calls fn_b() in module 'b'. ++These module functions emit 'name()' output in nested form, ++e.g. a=>b emits 'a(b())' ++ ++For single character object names, square brackets [] in the description ++allows specifying multiple objects; e.g. a->[bcd]->e is equivalent to ++ a->b->e;a->c->e;a->d->e ++ ++The () parenthesis construct with space separated names is also allowed for ++specifying objects. For names with integer suffixes a range can also be used, ++e.g. (foo1 bar2-5), specifies DSOs foo1, bar2, bar2, bar3, bar4, bar5. ++ ++A {} construct specifies the main test program, and its link dependencies ++are also specified using ->. Inside {}, a few ;-separated constructs are ++allowed: ++ +a Loads module a using dlopen(RTLD_LAZY|RTLD_GLOBAL) ++ ^a Loads module a using dlopen(RTLD_LAZY) ++ %a Use dlsym() to load and call fn_a() ++ @a Calls fn_a() directly. ++ -a Unloads module a using dlclose() ++ ++The generated main program outputs '{' '}' with all output from above ++constructs in between. The other output before/after {} are the ordered ++constructor/destructor output. ++ ++If no {} construct is present, a default empty main program is linked ++against all objects which have no dependency linked to it. e.g. for ++'[ab]->c;d->e', the default main program is equivalent to '{}->[abd]' ++ ++Sometimes for very complex or large testcases, besides specifying a ++few explicit dependencies from main{}, the above default dependency ++behavior is still useful to automatically have, but is turned off ++upon specifying a single explicit {}->dso_name. ++In this case, add {}->* to explicitly add this generation behavior: ++ ++ # Main program links to 'foo', and all other objects which have no ++ # dependency linked to it. ++ {}->foo,{}->* ++ ++Note that '*' works not only on main{}, but can be used as the ++dependency target of any object. Note that it only works as a target, ++not a dependency source. ++ ++The '!' operator after object names turns on permutation of its ++dependencies, e.g. while a->[bcd] only generates one set of objects, ++with 'a.so' built with a link line of "b.so c.so d.so", for a!->[bcd] ++permutations of a's dependencies creates multiple testcases with ++different link line orders: "b.so c.so d.so", "c.so b.so d.so", ++"b.so d.so c.so", etc. Note that for a specified on ++the script command-line, multiple , , etc. ++tests will be generated (e.g. for a!->[bc]!->[de], eight tests with ++different link orders for a, b, and c will be generated) ++ ++It is possible to specify the ELF soname field for an object or the ++main program: ++ # DSO 'a' will be linked with the appropriate -Wl,-soname=x setting ++ a->b->c;soname(a)=x ++ # The the main program can also have a soname specified ++ soname({})=y ++ ++This can be used to test how ld.so behaves when objects and/or the ++main program have such a field set. ++ ++ ++Strings Output by Generated Testcase Programs ++ ++The text output produced by a generated testcase consists of three main ++parts: ++ 1. The constructors' output ++ 2. Output from the main program ++ 3. Destructors' output ++ ++To see by example, a simple test description "a->b->c" generates a testcase ++that when run, outputs: "c>b>a>{}' character, ++and the "c>b>a" part above is the full constructor output by all DSOs, the ++order indicating that DSO 'c', which does not depend on any other DSO, has ++its constructor run first, followed by 'b' and then 'a'. ++ ++Destructor output for each DSO is a '<' character followed by its name, ++reflecting its reverse nature of constructors. In the above example, the ++destructor output part is "g=>h;{+c;%c;-c}->a->h ++ ++This produces a testcase, that when executed outputs: ++ h>a>{+c[g>c>];%c();-c[h dependency as expected. ++Inside the main program, the "+c" action triggers a dlopen() of DSO 'c', ++causing another chain of constructors "g>c>" to be triggered. Here it is ++displayed inside [] brackets for each dlopen call. The same is done for "-c", ++a dlclose() of 'c'. ++ ++The "%c" output is due to calling to fn_c() inside DSO 'c', this comprises ++of two parts: the '%' character is printed by the caller, here it is the main ++program. The 'c' character is printed from inside fn_c(). The '%' character ++indicates that this is called by a dlsym() of "fn_c". A '@' character would ++mean a direct call (with a symbol reference). These can all be controlled ++by the main test program constructs documented earlier. ++ ++The output strings described here is the exact same form placed in ++test description files' "output: " line. ++""" ++ ++import sys ++import re ++import os ++import subprocess ++import argparse ++from collections import OrderedDict ++import itertools ++ ++# BUILD_GCC is only used under the --build option, ++# which builds the generated testcase, including DSOs using BUILD_GCC. ++# Mainly for testing purposes, especially debugging of this script, ++# and can be changed here to another toolchain path if needed. ++build_gcc = "gcc" ++ ++def get_parser(): ++ parser = argparse.ArgumentParser("") ++ parser.add_argument("description", ++ help="Description string of DSO dependency test to be " ++ "generated (see script source for documentation of " ++ "description language), either specified here as " ++ "command line argument, or by input file using " ++ "-f/--description-file option", ++ nargs="?", default="") ++ parser.add_argument("test_name", ++ help="Identifier for testcase being generated", ++ nargs="?", default="") ++ parser.add_argument("--objpfx", ++ help="Path to place generated files, defaults to " ++ "current directory if none specified", ++ nargs="?", default="./") ++ parser.add_argument("-m", "--output-makefile", ++ help="File to write Makefile fragment to, defaults to " ++ "stdout when option not present", ++ nargs="?", default="") ++ parser.add_argument("-f", "--description-file", ++ help="Input file containing testcase descriptions", ++ nargs="?", default="") ++ parser.add_argument("--build", help="After C testcase generated, build it " ++ "using gcc (for manual testing purposes)", ++ action="store_true") ++ parser.add_argument("--debug-output", ++ help="Prints some internal data " ++ "structures; used for debugging of this script", ++ action="store_true") ++ return parser ++ ++# Main script starts here. ++cmdlineargs = get_parser().parse_args() ++test_name = cmdlineargs.test_name ++description = cmdlineargs.description ++objpfx = cmdlineargs.objpfx ++description_file = cmdlineargs.description_file ++output_makefile = cmdlineargs.output_makefile ++makefile = "" ++default_tunable_options = [] ++ ++current_input_lineno = 0 ++def error(msg): ++ global current_input_lineno ++ print("Error: %s%s" % ((("Line %d, " % current_input_lineno) ++ if current_input_lineno != 0 else ""), ++ msg)) ++ exit(1) ++ ++if(test_name or description) and description_file: ++ error("both command-line testcase and input file specified") ++if test_name and not description: ++ error("command-line testcase name without description string") ++ ++# Main class type describing a testcase. ++class TestDescr: ++ def __init__(self): ++ self.objs = [] # list of all DSO objects ++ self.deps = OrderedDict() # map of DSO object -> list of dependencies ++ ++ # map of DSO object -> list of call refs ++ self.callrefs = OrderedDict() ++ ++ # map of DSO object -> list of permutations of dependencies ++ self.dep_permutations = OrderedDict() ++ ++ # map of DSO object -> SONAME of object (if one is specified) ++ self.soname_map = OrderedDict() ++ ++ # list of main program operations ++ self.main_program = [] ++ # set if default dependencies added to main ++ self.main_program_default_deps = True ++ ++ self.test_name = "" # name of testcase ++ self.expected_outputs = OrderedDict() # expected outputs of testcase ++ self.xfail = False # set if this is a XFAIL testcase ++ self.xtest = False # set if this is put under 'xtests' ++ ++ # Add 'object -> [object, object, ...]' relations to CURR_MAP ++ def __add_deps_internal(self, src_objs, dst_objs, curr_map): ++ for src in src_objs: ++ for dst in dst_objs: ++ if not src in curr_map: ++ curr_map[src] = [] ++ if not dst in curr_map[src]: ++ curr_map[src].append(dst) ++ def add_deps(self, src_objs, dst_objs): ++ self.__add_deps_internal(src_objs, dst_objs, self.deps) ++ def add_callrefs(self, src_objs, dst_objs): ++ self.__add_deps_internal(src_objs, dst_objs, self.callrefs) ++ ++# Process commands inside the {} construct. ++# Note that throughout this script, the main program object is represented ++# by the '#' string. ++def process_main_program(test_descr, mainprog_str): ++ if mainprog_str: ++ test_descr.main_program = mainprog_str.split(';') ++ for s in test_descr.main_program: ++ m = re.match(r"^([+\-%^@])([0-9a-zA-Z]+)$", s) ++ if not m: ++ error("'%s' is not recognized main program operation" % (s)) ++ opr = m.group(1) ++ obj = m.group(2) ++ if not obj in test_descr.objs: ++ test_descr.objs.append(obj) ++ if opr == '%' or opr == '@': ++ test_descr.add_callrefs(['#'], [obj]) ++ # We have a main program specified, turn this off ++ test_descr.main_program_default_deps = False ++ ++# For(a1 a2 b1-12) object set descriptions, expand into an object list ++def expand_object_set_string(descr_str): ++ obj_list = [] ++ descr_list = descr_str.split() ++ for descr in descr_list: ++ m = re.match(r"^([a-zA-Z][0-9a-zA-Z]*)(-[0-9]+)?$", descr) ++ if not m: ++ error("'%s' is not a valid object set description" % (descr)) ++ obj = m.group(1) ++ idx_end = m.group(2) ++ if not idx_end: ++ if not obj in obj_list: ++ obj_list.append(obj) ++ else: ++ idx_end = int(idx_end[1:]) ++ m = re.match(r"^([0-9a-zA-Z][a-zA-Z]*)([0-9]+)$", obj) ++ if not m: ++ error("object description '%s' is malformed" % (obj)) ++ obj_name = m.group(1) ++ idx_start = int(m.group (2)) ++ if idx_start > idx_end: ++ error("index range %s-%s invalid" % (idx_start, idx_end)) ++ for i in range(idx_start, idx_end + 1): ++ o = obj_name + str(i) ++ if not o in obj_list: ++ obj_list.append(o) ++ return obj_list ++ ++# Lexer for tokens ++tokenspec = [ ("SONAME", r"soname\(([0-9a-zA-Z{}]+)\)=([0-9a-zA-Z]+)"), ++ ("OBJ", r"([0-9a-zA-Z]+)"), ++ ("DEP", r"->"), ++ ("CALLREF", r"=>"), ++ ("OBJSET", r"\[([0-9a-zA-Z]+)\]"), ++ ("OBJSET2", r"\(([0-9a-zA-Z \-]+)\)"), ++ ("OBJSET3", r"\*"), ++ ("PROG", r"{([0-9a-zA-Z;+^\-%@]*)}"), ++ ("PERMUTE", r"!"), ++ ("SEMICOL", r";"), ++ ("ERROR", r".") ] ++tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tokenspec) ++ ++# Main line parser of description language ++def parse_description_string(t, descr_str): ++ # State used when parsing dependencies ++ curr_objs = [] ++ in_dep = False ++ in_callref = False ++ def clear_dep_state(): ++ nonlocal in_dep, in_callref ++ in_dep = in_callref = False ++ ++ for m in re.finditer(tok_re, descr_str): ++ kind = m.lastgroup ++ value = m.group() ++ if kind == "SONAME": ++ s = re.match(r"soname\(([0-9a-zA-Z{}]+)\)=([0-9a-zA-Z]+)", value) ++ obj = s.group(1) ++ val = s.group(2) ++ if obj == "{}": ++ if '#' in t.soname_map: ++ error("soname of main program already set") ++ # Adjust to internal name ++ obj = '#' ++ else: ++ if re.match(r"[{}]", obj): ++ error("invalid object name '%s'" % (obj)) ++ if not obj in t.objs: ++ error("'%s' is not name of already defined object" % (obj)) ++ if obj in t.soname_map: ++ error("'%s' already has soname of '%s' set" ++ % (obj, t.soname_map[obj])) ++ t.soname_map[obj] = val ++ ++ elif kind == "OBJ": ++ if in_dep: ++ t.add_deps(curr_objs, [value]) ++ elif in_callref: ++ t.add_callrefs(curr_objs, [value]) ++ clear_dep_state() ++ curr_objs = [value] ++ if not value in t.objs: ++ t.objs.append(value) ++ ++ elif kind == "OBJSET": ++ objset = value[1:len(value)-1] ++ if in_dep: ++ t.add_deps(curr_objs, list (objset)) ++ elif in_callref: ++ t.add_callrefs(curr_objs, list (objset)) ++ clear_dep_state() ++ curr_objs = list(objset) ++ for o in list(objset): ++ if not o in t.objs: ++ t.objs.append(o) ++ ++ elif kind == "OBJSET2": ++ descr_str = value[1:len(value)-1] ++ descr_str.strip() ++ objs = expand_object_set_string(descr_str) ++ if not objs: ++ error("empty object set '%s'" % (value)) ++ if in_dep: ++ t.add_deps(curr_objs, objs) ++ elif in_callref: ++ t.add_callrefs(curr_objs, objs) ++ clear_dep_state() ++ curr_objs = objs ++ for o in objs: ++ if not o in t.objs: ++ t.objs.append(o) ++ ++ elif kind == "OBJSET3": ++ if in_dep: ++ t.add_deps(curr_objs, ['*']) ++ elif in_callref: ++ t.add_callrefs(curr_objs, ['*']) ++ else: ++ error("non-dependence target set '*' can only be used " ++ "as target of ->/=> operations") ++ clear_dep_state() ++ curr_objs = ['*'] ++ ++ elif kind == "PERMUTE": ++ if in_dep or in_callref: ++ error("syntax error, permute operation invalid here") ++ if not curr_objs: ++ error("syntax error, no objects to permute here") ++ ++ for obj in curr_objs: ++ if not obj in t.dep_permutations: ++ # Signal this object has permuted dependencies ++ t.dep_permutations[obj] = [] ++ ++ elif kind == "PROG": ++ if t.main_program: ++ error("cannot have more than one main program") ++ if in_dep: ++ error("objects cannot have dependency on main program") ++ if in_callref: ++ # TODO: A DSO can resolve to a symbol in the main binary, ++ # which we syntactically allow here, but haven't yet ++ # implemented. ++ t.add_callrefs(curr_objs, ["#"]) ++ process_main_program(t, value[1:len(value)-1]) ++ clear_dep_state() ++ curr_objs = ["#"] ++ ++ elif kind == "DEP": ++ if in_dep or in_callref: ++ error("syntax error, multiple contiguous ->,=> operations") ++ if '*' in curr_objs: ++ error("non-dependence target set '*' can only be used " ++ "as target of ->/=> operations") ++ in_dep = True ++ ++ elif kind == "CALLREF": ++ if in_dep or in_callref: ++ error("syntax error, multiple contiguous ->,=> operations") ++ if '*' in curr_objs: ++ error("non-dependence target set '*' can only be used " ++ "as target of ->/=> operations") ++ in_callref = True ++ ++ elif kind == "SEMICOL": ++ curr_objs = [] ++ clear_dep_state() ++ ++ else: ++ error("unknown token '%s'" % (value)) ++ return t ++ ++# Main routine to process each testcase description ++def process_testcase(t): ++ global objpfx ++ assert t.test_name ++ ++ base_test_name = t.test_name ++ test_subdir = base_test_name + "-dir" ++ testpfx = objpfx + test_subdir + "/" ++ ++ if not os.path.exists(testpfx): ++ os.mkdir(testpfx) ++ ++ def find_objs_not_depended_on(t): ++ objs_not_depended_on = [] ++ for obj in t.objs: ++ skip = False ++ for r in t.deps.items(): ++ if obj in r[1]: ++ skip = True ++ break ++ if not skip: ++ objs_not_depended_on.append(obj) ++ return objs_not_depended_on ++ ++ non_dep_tgt_objs = find_objs_not_depended_on(t) ++ for obj in t.objs: ++ if obj in t.deps: ++ deps = t.deps[obj] ++ if '*' in deps: ++ t.deps[obj].remove('*') ++ t.add_deps([obj], non_dep_tgt_objs) ++ if obj in t.callrefs: ++ deps = t.callrefs[obj] ++ if '*' in deps: ++ t.deps[obj].remove('*') ++ t.add_callrefs([obj], non_dep_tgt_objs) ++ if "#" in t.deps: ++ deps = t.deps["#"] ++ if '*' in deps: ++ t.deps["#"].remove('*') ++ t.add_deps(["#"], non_dep_tgt_objs) ++ ++ # If no main program was specified in dependency description, make a ++ # default main program with deps pointing to all DSOs which are not ++ # depended by another DSO. ++ if t.main_program_default_deps: ++ main_deps = non_dep_tgt_objs ++ if not main_deps: ++ error("no objects for default main program to point " ++ "dependency to(all objects strongly connected?)") ++ t.add_deps(["#"], main_deps) ++ ++ # Some debug output ++ if cmdlineargs.debug_output: ++ print("Testcase: %s" % (t.test_name)) ++ print("All objects: %s" % (t.objs)) ++ print("--- Static link dependencies ---") ++ for r in t.deps.items(): ++ print("%s -> %s" % (r[0], r[1])) ++ print("--- Objects whose dependencies are to be permuted ---") ++ for r in t.dep_permutations.items(): ++ print("%s" % (r[0])) ++ print("--- Call reference dependencies ---") ++ for r in t.callrefs.items(): ++ print("%s => %s" % (r[0], r[1])) ++ print("--- main program ---") ++ print(t.main_program) ++ ++ # Main testcase generation routine, does Makefile fragment generation, ++ # testcase source generation, and if --build specified builds testcase. ++ def generate_testcase(test_descr, test_suffix): ++ ++ test_name = test_descr.test_name + test_suffix ++ ++ # Print out needed Makefile fragments for use in glibc/elf/Makefile. ++ module_names = "" ++ for o in test_descr.objs: ++ module_names += " " + test_subdir + "/" + test_name + "-" + o ++ makefile.write("modules-names +=%s\n" % (module_names)) ++ ++ # Depth-first traversal, executing FN(OBJ) in post-order ++ def dfs(t, fn): ++ def dfs_rec(obj, fn, obj_visited): ++ if obj in obj_visited: ++ return ++ obj_visited[obj] = True ++ if obj in t.deps: ++ for dep in t.deps[obj]: ++ dfs_rec(dep, fn, obj_visited) ++ fn(obj) ++ ++ obj_visited = {} ++ for obj in t.objs: ++ dfs_rec(obj, fn, obj_visited) ++ ++ # Generate link dependencies for all DSOs, done in a DFS fashion. ++ # Usually this doesn't need to be this complex, just listing the direct ++ # dependencies is enough. However to support creating circular ++ # dependency situations, traversing it by DFS and tracking processing ++ # status is the natural way to do it. ++ obj_processed = {} ++ fake_created = {} ++ def gen_link_deps(obj): ++ if obj in test_descr.deps: ++ dso = test_subdir + "/" + test_name + "-" + obj + ".so" ++ dependencies = "" ++ for dep in test_descr.deps[obj]: ++ if dep in obj_processed: ++ depstr = (" $(objpfx)" + test_subdir + "/" ++ + test_name + "-" + dep + ".so") ++ else: ++ # A circular dependency is satisfied by making a ++ # fake DSO tagged with the correct SONAME ++ depstr = (" $(objpfx)" + test_subdir + "/" ++ + test_name + "-" + dep + ".FAKE.so") ++ # Create empty C file and Makefile fragments for fake ++ # object. This only needs to be done at most once for ++ # an object name. ++ if not dep in fake_created: ++ f = open(testpfx + test_name + "-" + dep ++ + ".FAKE.c", "w") ++ f.write(" \n") ++ f.close() ++ # Generate rule to create fake object ++ makefile.write \ ++ ("LDFLAGS-%s = -Wl,--no-as-needed " ++ "-Wl,-soname=%s\n" ++ % (test_name + "-" + dep + ".FAKE.so", ++ ("$(objpfx)" + test_subdir + "/" ++ + test_name + "-" + dep + ".so"))) ++ makefile.write \ ++ ("modules-names += %s\n" ++ % (test_subdir + "/" ++ + test_name + "-" + dep + ".FAKE")) ++ fake_created[dep] = True ++ dependencies += depstr ++ makefile.write("$(objpfx)%s:%s\n" % (dso, dependencies)) ++ # Mark obj as processed ++ obj_processed[obj] = True ++ ++ dfs(test_descr, gen_link_deps) ++ ++ # Print LDFLAGS-* and *-no-z-defs ++ for o in test_descr.objs: ++ dso = test_name + "-" + o + ".so" ++ ldflags = "-Wl,--no-as-needed" ++ if o in test_descr.soname_map: ++ soname = ("$(objpfx)" + test_subdir + "/" ++ + test_name + "-" ++ + test_descr.soname_map[o] + ".so") ++ ldflags += (" -Wl,-soname=" + soname) ++ makefile.write("LDFLAGS-%s = %s\n" % (dso, ldflags)) ++ if o in test_descr.callrefs: ++ makefile.write("%s-no-z-defs = yes\n" % (dso)) ++ ++ # Print dependencies for main test program. ++ depstr = "" ++ if '#' in test_descr.deps: ++ for o in test_descr.deps['#']: ++ depstr += (" $(objpfx)" + test_subdir + "/" ++ + test_name + "-" + o + ".so") ++ makefile.write("$(objpfx)%s/%s:%s\n" % (test_subdir, test_name, depstr)) ++ ldflags = "-Wl,--no-as-needed" ++ if '#' in test_descr.soname_map: ++ soname = ("$(objpfx)" + test_subdir + "/" ++ + test_name + "-" ++ + test_descr.soname_map['#'] + ".so") ++ ldflags += (" -Wl,-soname=" + soname) ++ makefile.write("LDFLAGS-%s = %s\n" % (test_name, ldflags)) ++ ++ not_depended_objs = find_objs_not_depended_on(test_descr) ++ if not_depended_objs: ++ depstr = "" ++ for dep in not_depended_objs: ++ depstr += (" $(objpfx)" + test_subdir + "/" ++ + test_name + "-" + dep + ".so") ++ makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr)) ++ ++ # Add main executable to test-srcs ++ makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name)) ++ # Add dependency on main executable of test ++ makefile.write("$(objpfx)%s.out: $(objpfx)%s/%s\n" ++ % (base_test_name, test_subdir, test_name)) ++ ++ for r in test_descr.expected_outputs.items(): ++ tunable_options = [] ++ specific_tunable = r[0] ++ xfail = r[1][1] ++ if specific_tunable != "": ++ tunable_options = [specific_tunable] ++ else: ++ tunable_options = default_tunable_options ++ if not tunable_options: ++ tunable_options = [""] ++ ++ for tunable in tunable_options: ++ tunable_env = "" ++ tunable_sfx = "" ++ exp_tunable_sfx = "" ++ if tunable: ++ tunable_env = "GLIBC_TUNABLES=%s " % tunable ++ tunable_sfx = "-" + tunable.replace("=","_") ++ if specific_tunable: ++ tunable_sfx = "-" + specific_tunable.replace("=","_") ++ exp_tunable_sfx = tunable_sfx ++ tunable_descr = ("(%s)" % tunable_env.strip() ++ if tunable_env else "") ++ # Write out fragment of shell script for this single test. ++ test_descr.sh.write \ ++ ("%s${test_wrapper_env} ${run_program_env} \\\n" ++ "${common_objpfx}support/test-run-command \\\n" ++ "${common_objpfx}elf/ld.so \\\n" ++ "--library-path ${common_objpfx}elf/%s:" ++ "${common_objpfx}elf:${common_objpfx}.:" ++ "${common_objpfx}dlfcn \\\n" ++ "${common_objpfx}elf/%s/%s > \\\n" ++ " ${common_objpfx}elf/%s/%s%s.output\n" ++ % (tunable_env ,test_subdir, ++ test_subdir, test_name, test_subdir, test_name, ++ tunable_sfx)) ++ # Generate a run of each test and compare with expected out ++ test_descr.sh.write \ ++ ("if [ $? -ne 0 ]; then\n" ++ " echo '%sFAIL: %s%s execution test'\n" ++ " something_failed=true\n" ++ "else\n" ++ " diff -wu ${common_objpfx}elf/%s/%s%s.output \\\n" ++ " ${common_objpfx}elf/%s/%s%s.exp\n" ++ " if [ $? -ne 0 ]; then\n" ++ " echo '%sFAIL: %s%s expected output comparison'\n" ++ " something_failed=true\n" ++ " fi\n" ++ "fi\n" ++ % (("X" if xfail else ""), test_name, tunable_descr, ++ test_subdir, test_name, tunable_sfx, ++ test_subdir, base_test_name, exp_tunable_sfx, ++ ("X" if xfail else ""), test_name, tunable_descr)) ++ ++ # Generate C files according to dependency and calling relations from ++ # description string. ++ for obj in test_descr.objs: ++ src_name = test_name + "-" + obj + ".c" ++ f = open(testpfx + src_name, "w") ++ if obj in test_descr.callrefs: ++ called_objs = test_descr.callrefs[obj] ++ for callee in called_objs: ++ f.write("extern void fn_%s (void);\n" % (callee)) ++ if len(obj) == 1: ++ f.write("extern int putchar(int);\n") ++ f.write("static void __attribute__((constructor)) " + ++ "init(void){putchar('%s');putchar('>');}\n" % (obj)) ++ f.write("static void __attribute__((destructor)) " + ++ "fini(void){putchar('<');putchar('%s');}\n" % (obj)) ++ else: ++ f.write('extern int printf(const char *, ...);\n') ++ f.write('static void __attribute__((constructor)) ' + ++ 'init(void){printf("%s>");}\n' % (obj)) ++ f.write('static void __attribute__((destructor)) ' + ++ 'fini(void){printf("<%s");}\n' % (obj)) ++ if obj in test_descr.callrefs: ++ called_objs = test_descr.callrefs[obj] ++ if len(obj) != 1: ++ f.write("extern int putchar(int);\n") ++ f.write("void fn_%s (void) {\n" % (obj)) ++ if len(obj) == 1: ++ f.write(" putchar ('%s');\n" % (obj)); ++ f.write(" putchar ('(');\n"); ++ else: ++ f.write(' printf ("%s(");\n' % (obj)); ++ for callee in called_objs: ++ f.write(" fn_%s ();\n" % (callee)) ++ f.write(" putchar (')');\n"); ++ f.write("}\n") ++ else: ++ for callref in test_descr.callrefs.items(): ++ if obj in callref[1]: ++ if len(obj) == 1: ++ # We need to declare printf here in this case. ++ f.write('extern int printf(const char *, ...);\n') ++ f.write("void fn_%s (void) {\n" % (obj)) ++ f.write(' printf ("%s()");\n' % (obj)) ++ f.write("}\n") ++ break ++ f.close() ++ ++ # Open C file for writing main program ++ f = open(testpfx + test_name + ".c", "w") ++ ++ # if there are some operations in main(), it means we need -ldl ++ f.write("#include \n") ++ f.write("#include \n") ++ f.write("#include \n") ++ for s in test_descr.main_program: ++ if s[0] == '@': ++ f.write("extern void fn_%s (void);\n" % (s[1:])); ++ f.write("int main (void) {\n") ++ f.write(" putchar('{');\n") ++ ++ # Helper routine for generating sanity checking code. ++ def put_fail_check(fail_cond, action_desc): ++ f.write(' if (%s) { printf ("\\n%s failed: %%s\\n", ' ++ 'dlerror()); exit (1);}\n' % (fail_cond, action_desc)) ++ i = 0 ++ while i < len(test_descr.main_program): ++ s = test_descr.main_program[i] ++ obj = s[1:] ++ dso = test_name + "-" + obj ++ if s[0] == '+' or s[0] == '^': ++ if s[0] == '+': ++ dlopen_flags = "RTLD_LAZY|RTLD_GLOBAL" ++ f.write(" putchar('+');\n"); ++ else: ++ dlopen_flags = "RTLD_LAZY" ++ f.write(" putchar(':');\n"); ++ if len(obj) == 1: ++ f.write(" putchar('%s');\n" % (obj)); ++ else: ++ f.write(' printf("%s");\n' % (obj)); ++ f.write(" putchar('[');\n"); ++ f.write(' void *%s = dlopen ("%s.so", %s);\n' ++ % (obj, dso, dlopen_flags)) ++ put_fail_check("!%s" % (obj), ++ "%s.so dlopen" % (dso)) ++ f.write(" putchar(']');\n"); ++ elif s[0] == '-': ++ f.write(" putchar('-');\n"); ++ if len(obj) == 1: ++ f.write(" putchar('%s');\n" % (obj)); ++ else: ++ f.write(' printf("%s");\n' % (obj)); ++ f.write(" putchar('[');\n"); ++ put_fail_check("dlclose (%s) != 0" % (obj), ++ "%s.so dlclose" % (dso)) ++ f.write(" putchar(']');\n"); ++ elif s[0] == '%': ++ f.write(" putchar('%');\n"); ++ f.write(' void (*fn_%s)(void) = dlsym (%s, "fn_%s");\n' ++ % (obj, obj, obj)) ++ put_fail_check("!fn_%s" % (obj), ++ "dlsym(fn_%s) from %s.so" % (obj, dso)) ++ f.write(" fn_%s ();\n" % (obj)) ++ elif s[0] == '@': ++ f.write(" putchar('@');\n"); ++ f.write(" fn_%s ();\n" % (obj)) ++ f.write(" putchar(';');\n"); ++ i += 1 ++ f.write(" putchar('}');\n") ++ f.write(" return 0;\n") ++ f.write("}\n") ++ f.close() ++ ++ # --build option processing: build generated sources using 'build_gcc' ++ if cmdlineargs.build: ++ # Helper routine to run a shell command, for running GCC below ++ def run_cmd(args): ++ cmd = str.join(' ', args) ++ if cmdlineargs.debug_output: ++ print(cmd) ++ p = subprocess.Popen(args) ++ p.wait() ++ if p.returncode != 0: ++ error("error running command: %s" % (cmd)) ++ ++ # Compile individual .os files ++ for obj in test_descr.objs: ++ src_name = test_name + "-" + obj + ".c" ++ obj_name = test_name + "-" + obj + ".os" ++ run_cmd([build_gcc, "-c", "-fPIC", testpfx + src_name, ++ "-o", testpfx + obj_name]) ++ ++ obj_processed = {} ++ fake_created = {} ++ # Function to create -.so ++ def build_dso(obj): ++ obj_name = test_name + "-" + obj + ".os" ++ dso_name = test_name + "-" + obj + ".so" ++ deps = [] ++ if obj in test_descr.deps: ++ for dep in test_descr.deps[obj]: ++ if dep in obj_processed: ++ deps.append(dep) ++ else: ++ deps.append(dep + ".FAKE") ++ if not dep in fake_created: ++ base_name = testpfx + test_name + "-" + dep ++ cmd = [build_gcc, "-Wl,--no-as-needed", ++ ("-Wl,-soname=" + base_name + ".so"), ++ "-shared", base_name + ".FAKE.c", ++ "-o", base_name + ".FAKE.so"] ++ run_cmd(cmd) ++ fake_created[dep] = True ++ dso_deps = map(lambda d: testpfx + test_name + "-" + d + ".so", ++ deps) ++ cmd = [build_gcc, "-shared", "-o", testpfx + dso_name, ++ testpfx + obj_name, "-Wl,--no-as-needed"] ++ if obj in test_descr.soname_map: ++ soname = ("-Wl,-soname=" + testpfx + test_name + "-" ++ + test_descr.soname_map[obj] + ".so") ++ cmd += [soname] ++ cmd += list(dso_deps) ++ run_cmd(cmd) ++ obj_processed[obj] = True ++ ++ # Build all DSOs, this needs to be in topological dependency order, ++ # or link will fail ++ dfs(test_descr, build_dso) ++ ++ # Build main program ++ deps = [] ++ if '#' in test_descr.deps: ++ deps = test_descr.deps['#'] ++ main_deps = map(lambda d: testpfx + test_name + "-" + d + ".so", ++ deps) ++ cmd = [build_gcc, "-Wl,--no-as-needed", "-o", testpfx + test_name, ++ testpfx + test_name + ".c", "-L%s" % (os.getcwd()), ++ "-Wl,-rpath-link=%s" % (os.getcwd())] ++ if '#' in test_descr.soname_map: ++ soname = ("-Wl,-soname=" + testpfx + test_name + "-" ++ + test_descr.soname_map['#'] + ".so") ++ cmd += [soname] ++ cmd += list(main_deps) ++ run_cmd(cmd) ++ ++ # Check if we need to enumerate permutations of dependencies ++ need_permutation_processing = False ++ if t.dep_permutations: ++ # Adjust dep_permutations into map of object -> dependency permutations ++ for r in t.dep_permutations.items(): ++ obj = r[0] ++ if obj in t.deps and len(t.deps[obj]) > 1: ++ deps = t.deps[obj] ++ t.dep_permutations[obj] = list(itertools.permutations (deps)) ++ need_permutation_processing = True ++ ++ def enum_permutations(t, perm_list): ++ test_subindex = 1 ++ curr_perms = [] ++ def enum_permutations_rec(t, perm_list): ++ nonlocal test_subindex, curr_perms ++ if len(perm_list) >= 1: ++ curr = perm_list[0] ++ obj = curr[0] ++ perms = curr[1] ++ if not perms: ++ # This may be an empty list if no multiple dependencies to ++ # permute were found, skip to next in this case ++ enum_permutations_rec(t, perm_list[1:]) ++ else: ++ for deps in perms: ++ t.deps[obj] = deps ++ permstr = "" if obj == "#" else obj + "_" ++ permstr += str.join('', deps) ++ curr_perms.append(permstr) ++ enum_permutations_rec(t, perm_list[1:]) ++ curr_perms = curr_perms[0:len(curr_perms)-1] ++ else: ++ # t.deps is now instantiated with one dependency order ++ # permutation(across all objects that have multiple ++ # permutations), now process a testcase ++ generate_testcase(t, ("_" + str (test_subindex) ++ + "-" + str.join('-', curr_perms))) ++ test_subindex += 1 ++ enum_permutations_rec(t, perm_list) ++ ++ # Create *.exp files with expected outputs ++ for r in t.expected_outputs.items(): ++ sfx = "" ++ if r[0] != "": ++ sfx = "-" + r[0].replace("=","_") ++ f = open(testpfx + t.test_name + sfx + ".exp", "w") ++ (output, xfail) = r[1] ++ f.write('%s' % output) ++ f.close() ++ ++ # Create header part of top-level testcase shell script, to wrap execution ++ # and output comparison together. ++ t.sh = open(testpfx + t.test_name + ".sh", "w") ++ t.sh.write("#!/bin/sh\n") ++ t.sh.write("# Test driver for %s, generated by " ++ "dso-ordering-test.py\n" % (t.test_name)) ++ t.sh.write("common_objpfx=$1\n") ++ t.sh.write("test_wrapper_env=$2\n") ++ t.sh.write("run_program_env=$3\n") ++ t.sh.write("something_failed=false\n") ++ ++ # Starting part of Makefile fragment ++ makefile.write("ifeq (yes,$(build-shared))\n") ++ ++ if need_permutation_processing: ++ enum_permutations(t, list (t.dep_permutations.items())) ++ else: ++ # We have no permutations to enumerate, just process testcase normally ++ generate_testcase(t, "") ++ ++ # If testcase is XFAIL, indicate so ++ if t.xfail: ++ makefile.write("test-xfail-%s = yes\n" % t.test_name) ++ ++ # Output end part of Makefile fragment ++ expected_output_files = "" ++ for r in t.expected_outputs.items(): ++ sfx = "" ++ if r[0] != "": ++ sfx = "-" + r[0].replace("=","_") ++ expected_output_files += " $(objpfx)%s/%s%s.exp" % (test_subdir, ++ t.test_name, sfx) ++ makefile.write \ ++ ("$(objpfx)%s.out: $(objpfx)%s/%s.sh%s " ++ "$(common-objpfx)support/test-run-command\n" ++ % (t.test_name, test_subdir, t.test_name, ++ expected_output_files)) ++ makefile.write("\t$(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' " ++ "'$(run-program-env)' > $@; $(evaluate-test)\n") ++ makefile.write("ifeq ($(run-built-tests),yes)\n") ++ if t.xtest: ++ makefile.write("xtests-special += $(objpfx)%s.out\n" % (t.test_name)) ++ else: ++ makefile.write("tests-special += $(objpfx)%s.out\n" % (t.test_name)) ++ makefile.write("endif\n") ++ makefile.write("endif\n") ++ ++ # Write ending part of shell script generation ++ t.sh.write("if $something_failed; then\n" ++ " exit 1\n" ++ "else\n" ++ " echo '%sPASS: all tests for %s succeeded'\n" ++ " exit 0\n" ++ "fi\n" % (("X" if t.xfail else ""), ++ t.test_name)) ++ t.sh.close() ++ ++# Decription file parsing ++def parse_description_file(filename): ++ global default_tunable_options ++ global current_input_lineno ++ f = open(filename) ++ if not f: ++ error("cannot open description file %s" % (filename)) ++ descrfile_lines = f.readlines() ++ t = None ++ for line in descrfile_lines: ++ p = re.compile(r"#.*$") ++ line = p.sub("", line) # Filter out comments ++ line = line.strip() # Remove excess whitespace ++ current_input_lineno += 1 ++ ++ m = re.match(r"^tunable_option:\s*(.*)$", line) ++ if m: ++ if m.group(1) == "": ++ error("tunable option cannot be empty") ++ default_tunable_options.append(m.group (1)) ++ continue ++ ++ m = re.match(r"^clear_tunables$", line) ++ if m: ++ default_tunable_options = [] ++ continue ++ ++ m = re.match(r"^([^:]+):\s*(.*)$", line) ++ if m: ++ lhs = m.group(1) ++ o = re.match(r"^output(.*)$", lhs) ++ xfail = False ++ if not o: ++ o = re.match(r"^xfail_output(.*)$", lhs) ++ if o: ++ xfail = True; ++ if o: ++ if not t: ++ error("output specification without testcase description") ++ tsstr = "" ++ if o.group(1): ++ ts = re.match(r"^\(([a-zA-Z0-9_.=]*)\)$", o.group (1)) ++ if not ts: ++ error("tunable option malformed '%s'" % o.group(1)) ++ tsstr = ts.group(1) ++ t.expected_outputs[tsstr] = (m.group(2), xfail) ++ # Any tunable option XFAILed means entire testcase ++ # is XFAIL/XPASS ++ t.xfail |= xfail ++ else: ++ if t: ++ # Starting a new test description, end and process ++ # current one. ++ process_testcase(t) ++ t = TestDescr() ++ x = re.match(r"^xtest\((.*)\)$", lhs) ++ if x: ++ t.xtest = True ++ t.test_name = x.group(1) ++ else: ++ t.test_name = lhs ++ descr_string = m.group(2) ++ parse_description_string(t, descr_string) ++ continue ++ else: ++ if line: ++ if not t: ++ error("no active testcase description") ++ parse_description_string(t, line) ++ # Process last completed test description ++ if t: ++ process_testcase(t) ++ ++# Setup Makefile output to file or stdout as selected ++if output_makefile: ++ output_makefile_dir = os.path.dirname(output_makefile) ++ if output_makefile_dir: ++ os.makedirs(output_makefile_dir, exist_ok = True) ++ makefile = open(output_makefile, "w") ++else: ++ makefile = open(sys.stdout.fileno (), "w") ++ ++# Finally, the main top-level calling of above parsing routines. ++if description_file: ++ parse_description_file(description_file) ++else: ++ t = TestDescr() ++ t.test_name = test_name ++ parse_description_string(t, description) ++ process_testcase(t) ++ ++# Close Makefile fragment output ++makefile.close() +diff --git a/support/Depend b/support/Depend +new file mode 100644 +index 0000000000000000..7e7d5dc67c13e669 +--- /dev/null ++++ b/support/Depend +@@ -0,0 +1 @@ ++elf +diff --git a/support/Makefile b/support/Makefile +index 7749ac24f1ac3622..636d69c4f8e7e139 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -215,10 +215,16 @@ others-noinstall += shell-container echo-container true-container + others += $(LINKS_DSO_PROGRAM) + others-noinstall += $(LINKS_DSO_PROGRAM) + ++others += test-run-command ++others-static += test-run-command ++others-noinstall += test-run-command ++LDLIBS-test-run-command = $(libsupport) ++ + $(objpfx)test-container : $(libsupport) + $(objpfx)shell-container : $(libsupport) + $(objpfx)echo-container : $(libsupport) + $(objpfx)true-container : $(libsupport) ++$(objpfx)test-run-command : $(libsupport) $(common-objpfx)elf/static-stubs.o + + tests = \ + README-testing \ +diff --git a/support/support_test_main.c b/support/support_test_main.c +index def84d803928176b..49e9d9c5baf776eb 100644 +--- a/support/support_test_main.c ++++ b/support/support_test_main.c +@@ -228,6 +228,18 @@ run_test_function (int argc, char **argv, const struct test_config *config) + while (wait_for_debugger) + usleep (1000); + ++ if (config->run_command_mode) ++ { ++ /* In run-command-mode, the child process executes the command line ++ arguments as a new program. */ ++ char **argv_ = xmalloc (sizeof (char *) * argc); ++ memcpy (argv_, &argv[1], sizeof (char *) * (argc - 1)); ++ argv_[argc - 1] = NULL; ++ execv (argv_[0], argv_); ++ printf ("error: should not return here\n"); ++ exit (1); ++ } ++ + if (config->test_function != NULL) + return config->test_function (); + else if (config->test_function_argv != NULL) +diff --git a/support/test-driver.c b/support/test-driver.c +index 9798f16227b9d467..93f25a99c1b9d2cb 100644 +--- a/support/test-driver.c ++++ b/support/test-driver.c +@@ -116,7 +116,9 @@ main (int argc, char **argv) + #if defined (TEST_FUNCTION) && defined (TEST_FUNCTON_ARGV) + # error TEST_FUNCTION and TEST_FUNCTION_ARGV cannot be defined at the same time + #endif +-#if defined (TEST_FUNCTION) ++#ifdef RUN_COMMAND_MODE ++ test_config.run_command_mode = 1; ++#elif defined (TEST_FUNCTION) + test_config.test_function = TEST_FUNCTION; + #elif defined (TEST_FUNCTION_ARGV) + test_config.test_function_argv = TEST_FUNCTION_ARGV; +diff --git a/support/test-driver.h b/support/test-driver.h +index 549179b254946390..818689ad1ae7fd8c 100644 +--- a/support/test-driver.h ++++ b/support/test-driver.h +@@ -36,6 +36,7 @@ struct test_config + int expected_signal; /* If non-zero, expect termination by signal. */ + char no_mallopt; /* Boolean flag to disable mallopt. */ + char no_setvbuf; /* Boolean flag to disable setvbuf. */ ++ char run_command_mode; /* Boolean flag to indicate run-command-mode. */ + const char *optstring; /* Short command line options. */ + }; + +diff --git a/support/test-run-command.c b/support/test-run-command.c +new file mode 100644 +index 0000000000000000..61560d7bfb1686a8 +--- /dev/null ++++ b/support/test-run-command.c +@@ -0,0 +1,22 @@ ++/* Main program for test-run-command support utility. ++ 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 ++ . */ ++ ++/* This is basically a configuration of test-driver.c into a general ++ command-line program runner. */ ++#define RUN_COMMAND_MODE ++#include diff --git a/glibc-rh1159809-10.patch b/glibc-rh1159809-10.patch new file mode 100644 index 0000000..4713f8a --- /dev/null +++ b/glibc-rh1159809-10.patch @@ -0,0 +1,79 @@ +commit dbb75513f5cf9285c77c9e55777c5c35b653f890 +Author: Florian Weimer +Date: Tue Sep 6 07:38:10 2022 +0200 + + elf: Rename _dl_sort_maps parameter from skip to force_first + + The new implementation will not be able to skip an arbitrary number + of objects. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c +index 99354dc08a010dd3..7a586749adc3fa7d 100644 +--- a/elf/dl-sort-maps.c ++++ b/elf/dl-sort-maps.c +@@ -27,12 +27,12 @@ + If FOR_FINI is true, this is called for finishing an object. */ + static void + _dl_sort_maps_original (struct link_map **maps, unsigned int nmaps, +- unsigned int skip, bool for_fini) ++ bool force_first, bool for_fini) + { + /* Allows caller to do the common optimization of skipping the first map, + usually the main binary. */ +- maps += skip; +- nmaps -= skip; ++ maps += force_first; ++ nmaps -= force_first; + + /* A list of one element need not be sorted. */ + if (nmaps <= 1) +@@ -182,7 +182,7 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map, + + static void + _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, +- unsigned int skip __attribute__ ((unused)), bool for_fini) ++ bool force_first __attribute__ ((unused)), bool for_fini) + { + for (int i = nmaps - 1; i >= 0; i--) + maps[i]->l_visited = 0; +@@ -286,7 +286,7 @@ _dl_sort_maps_init (void) + + void + _dl_sort_maps (struct link_map **maps, unsigned int nmaps, +- unsigned int skip, bool for_fini) ++ bool force_first, bool for_fini) + { + /* It can be tempting to use a static function pointer to store and call + the current selected sorting algorithm routine, but experimentation +@@ -296,9 +296,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, + input cases. A simple if-case with direct function calls appears to + be the fastest. */ + if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original)) +- _dl_sort_maps_original (maps, nmaps, skip, for_fini); ++ _dl_sort_maps_original (maps, nmaps, force_first, for_fini); + else +- _dl_sort_maps_dfs (maps, nmaps, skip, for_fini); ++ _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini); + } + + #endif /* HAVE_TUNABLES. */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 9f09a4a280396659..2c1b4c47c6a6c643 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1056,9 +1056,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv, + initializer functions have completed. */ + extern void _dl_fini (void) attribute_hidden; + +-/* Sort array MAPS according to dependencies of the contained objects. */ ++/* Sort array MAPS according to dependencies of the contained objects. ++ If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies ++ say otherwise. */ + extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps, +- unsigned int skip, bool for_fini) attribute_hidden; ++ bool force_first, bool for_fini) attribute_hidden; + + /* The dynamic linker calls this function before and having changing + any shared object mappings. The `r_state' member of `struct r_debug' diff --git a/glibc-rh1159809-11.patch b/glibc-rh1159809-11.patch new file mode 100644 index 0000000..fc4a7e1 --- /dev/null +++ b/glibc-rh1159809-11.patch @@ -0,0 +1,90 @@ +commit 1df71d32fe5f5905ffd5d100e5e9ca8ad6210891 +Author: Florian Weimer +Date: Tue Sep 20 11:00:42 2022 +0200 + + elf: Implement force_first handling in _dl_sort_maps_dfs (bug 28937) + + The implementation in _dl_close_worker requires that the first + element of l_initfini is always this very map (“We are always the + zeroth entry, and since we don't include ourselves in the + dependency analysis start at 1.”). Rather than fixing that + assumption, this commit adds an implementation of the force_first + argument to the new dependency sorting algorithm. This also means + that the directly dlopen'ed shared object is always initialized last, + which is the least surprising behavior in the presence of cycles. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c +index 7a586749adc3fa7d..6f5c17b47b98fbc7 100644 +--- a/elf/dl-sort-maps.c ++++ b/elf/dl-sort-maps.c +@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map, + + static void + _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, +- bool force_first __attribute__ ((unused)), bool for_fini) ++ bool force_first, bool for_fini) + { ++ struct link_map *first_map = maps[0]; + for (int i = nmaps - 1; i >= 0; i--) + maps[i]->l_visited = 0; + +@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, + Adjusting the order so that maps[0] is last traversed naturally avoids + this problem. + +- Further, the old "optimization" of skipping the main object at maps[0] +- from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general +- no longer valid, since traversing along object dependency-links +- may "find" the main object even when it is not included in the initial +- order (e.g. a dlopen()'ed shared object can have circular dependencies +- linked back to itself). In such a case, traversing N-1 objects will +- create a N-object result, and raise problems. +- + To summarize, just passing in the full list, and iterating from back + to front makes things much more straightforward. */ + +@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, + } + + memcpy (maps, rpo, sizeof (struct link_map *) * nmaps); ++ ++ /* Skipping the first object at maps[0] is not valid in general, ++ since traversing along object dependency-links may "find" that ++ first object even when it is not included in the initial order ++ (e.g., a dlopen'ed shared object can have circular dependencies ++ linked back to itself). In such a case, traversing N-1 objects ++ will create a N-object result, and raise problems. Instead, ++ force the object back into first place after sorting. This naive ++ approach may introduce further dependency ordering violations ++ compared to rotating the cycle until the first map is again in ++ the first position, but as there is a cycle, at least one ++ violation is already present. */ ++ if (force_first && maps[0] != first_map) ++ { ++ int i; ++ for (i = 0; maps[i] != first_map; ++i) ++ ; ++ assert (i < nmaps); ++ memmove (&maps[1], maps, i * sizeof (maps[0])); ++ maps[0] = first_map; ++ } + } + + void +diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def +index 5f7f18ef270bc12d..4bf9052db16fb352 100644 +--- a/elf/dso-sort-tests-1.def ++++ b/elf/dso-sort-tests-1.def +@@ -64,3 +64,10 @@ output: b>a>{}b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c + output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[a1;a->a2;a2->a;b->b1;c->a1;c=>a1 ++output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());} interfaces +are part of libc. + +diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py +index 43b5ec4d920ad6a3..ae85e0f4a6ae5b3e 100644 +--- a/scripts/dso-ordering-test.py ++++ b/scripts/dso-ordering-test.py +@@ -657,6 +657,8 @@ def process_testcase(t): + % (test_name + "-" + dep + ".FAKE.so", + ("$(objpfx)" + test_subdir + "/" + + test_name + "-" + dep + ".so"))) ++ makefile.write( ++ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % dso) + rule = ("$(objpfx)" + test_subdir + "/" + + test_name + "-" + dep + ".FAKE.os: " + "$(objpfx)" + test_srcdir +@@ -685,6 +687,8 @@ def process_testcase(t): + + test_descr.soname_map[o] + ".so") + ldflags += (" -Wl,-soname=" + soname) + makefile.write("LDFLAGS-%s = %s\n" % (dso, ldflags)) ++ makefile.write( ++ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % dso) + if o in test_descr.callrefs: + makefile.write("%s-no-z-defs = yes\n" % (dso)) + +@@ -702,6 +706,8 @@ def process_testcase(t): + + test_descr.soname_map['#'] + ".so") + ldflags += (" -Wl,-soname=" + soname) + makefile.write("LDFLAGS-%s = %s\n" % (test_name, ldflags)) ++ makefile.write( ++ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % test_name) + rule = ("$(objpfx)" + test_subdir + "/" + test_name + ".o: " + "$(objpfx)" + test_srcdir + test_name + ".c\n" + "\t$(compile.c) $(OUTPUT_OPTION)\n") diff --git a/glibc-rh1159809-2.patch b/glibc-rh1159809-2.patch new file mode 100644 index 0000000..1c415d4 --- /dev/null +++ b/glibc-rh1159809-2.patch @@ -0,0 +1,189 @@ +commit b4bbedb1e75737a80bcc3d53d6eef1fbe0b5f4d5 +Author: H.J. Lu +Date: Sat Nov 6 14:13:27 2021 -0700 + + dso-ordering-test.py: Put all sources in one directory [BZ #28550] + + Put all sources for DSO sorting tests in the dso-sort-tests-src directory + and compile test relocatable objects with + + $(objpfx)tst-dso-ordering1-dir/tst-dso-ordering1-a.os: $(objpfx)dso-sort-tests-src/tst-dso-ordering1-a.c + $(compile.c) $(OUTPUT_OPTION) + + to avoid random $< values from $(before-compile) when compiling test + relocatable objects with + + $(objpfx)%$o: $(objpfx)%.c $(before-compile); $$(compile-command.c) + compile-command.c = $(compile.c) $(OUTPUT_OPTION) $(compile-mkdep-flags) + compile.c = $(CC) $< -c $(CFLAGS) $(CPPFLAGS) + + for 3 "make -j 28" parallel builds on a machine with 112 cores at the + same time. + + This partially fixes BZ #28550. + + Reviewed-by: Adhemerval Zanella + +diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py +index 944ee740527d60fd..bde0406be9da14fc 100644 +--- a/scripts/dso-ordering-test.py ++++ b/scripts/dso-ordering-test.py +@@ -526,9 +526,13 @@ def process_testcase(t): + base_test_name = t.test_name + test_subdir = base_test_name + "-dir" + testpfx = objpfx + test_subdir + "/" ++ test_srcdir = "dso-sort-tests-src/" ++ testpfx_src = objpfx + test_srcdir + + if not os.path.exists(testpfx): + os.mkdir(testpfx) ++ if not os.path.exists(testpfx_src): ++ os.mkdir(testpfx_src) + + def find_objs_not_depended_on(t): + objs_not_depended_on = [] +@@ -595,6 +599,11 @@ def process_testcase(t): + # Print out needed Makefile fragments for use in glibc/elf/Makefile. + module_names = "" + for o in test_descr.objs: ++ rule = ("$(objpfx)" + test_subdir + "/" + test_name ++ + "-" + o + ".os: $(objpfx)" + test_srcdir ++ + test_name + "-" + o + ".c\n" ++ "\t$(compile.c) $(OUTPUT_OPTION)\n") ++ makefile.write (rule) + module_names += " " + test_subdir + "/" + test_name + "-" + o + makefile.write("modules-names +=%s\n" % (module_names)) + +@@ -637,7 +646,7 @@ def process_testcase(t): + # object. This only needs to be done at most once for + # an object name. + if not dep in fake_created: +- f = open(testpfx + test_name + "-" + dep ++ f = open(testpfx_src + test_name + "-" + dep + + ".FAKE.c", "w") + f.write(" \n") + f.close() +@@ -648,6 +657,12 @@ def process_testcase(t): + % (test_name + "-" + dep + ".FAKE.so", + ("$(objpfx)" + test_subdir + "/" + + test_name + "-" + dep + ".so"))) ++ rule = ("$(objpfx)" + test_subdir + "/" ++ + test_name + "-" + dep + ".FAKE.os: " ++ "$(objpfx)" + test_srcdir ++ + test_name + "-" + dep + ".FAKE.c\n" ++ "\t$(compile.c) $(OUTPUT_OPTION)\n") ++ makefile.write (rule) + makefile.write \ + ("modules-names += %s\n" + % (test_subdir + "/" +@@ -687,6 +702,10 @@ def process_testcase(t): + + test_descr.soname_map['#'] + ".so") + ldflags += (" -Wl,-soname=" + soname) + makefile.write("LDFLAGS-%s = %s\n" % (test_name, ldflags)) ++ rule = ("$(objpfx)" + test_subdir + "/" + test_name + ".o: " ++ "$(objpfx)" + test_srcdir + test_name + ".c\n" ++ "\t$(compile.c) $(OUTPUT_OPTION)\n") ++ makefile.write (rule) + + not_depended_objs = find_objs_not_depended_on(test_descr) + if not_depended_objs: +@@ -745,7 +764,7 @@ def process_testcase(t): + " something_failed=true\n" + "else\n" + " diff -wu ${common_objpfx}elf/%s/%s%s.output \\\n" +- " ${common_objpfx}elf/%s/%s%s.exp\n" ++ " ${common_objpfx}elf/%s%s%s.exp\n" + " if [ $? -ne 0 ]; then\n" + " echo '%sFAIL: %s%s expected output comparison'\n" + " something_failed=true\n" +@@ -753,14 +772,14 @@ def process_testcase(t): + "fi\n" + % (("X" if xfail else ""), test_name, tunable_descr, + test_subdir, test_name, tunable_sfx, +- test_subdir, base_test_name, exp_tunable_sfx, ++ test_srcdir, base_test_name, exp_tunable_sfx, + ("X" if xfail else ""), test_name, tunable_descr)) + + # Generate C files according to dependency and calling relations from + # description string. + for obj in test_descr.objs: + src_name = test_name + "-" + obj + ".c" +- f = open(testpfx + src_name, "w") ++ f = open(testpfx_src + src_name, "w") + if obj in test_descr.callrefs: + called_objs = test_descr.callrefs[obj] + for callee in called_objs: +@@ -804,7 +823,7 @@ def process_testcase(t): + f.close() + + # Open C file for writing main program +- f = open(testpfx + test_name + ".c", "w") ++ f = open(testpfx_src + test_name + ".c", "w") + + # if there are some operations in main(), it means we need -ldl + f.write("#include \n") +@@ -885,7 +904,7 @@ def process_testcase(t): + for obj in test_descr.objs: + src_name = test_name + "-" + obj + ".c" + obj_name = test_name + "-" + obj + ".os" +- run_cmd([build_gcc, "-c", "-fPIC", testpfx + src_name, ++ run_cmd([build_gcc, "-c", "-fPIC", testpfx_src + src_name, + "-o", testpfx + obj_name]) + + obj_processed = {} +@@ -903,10 +922,12 @@ def process_testcase(t): + deps.append(dep + ".FAKE") + if not dep in fake_created: + base_name = testpfx + test_name + "-" + dep ++ src_base_name = (testpfx_src + test_name ++ + "-" + dep) + cmd = [build_gcc, "-Wl,--no-as-needed", + ("-Wl,-soname=" + base_name + ".so"), + "-shared", base_name + ".FAKE.c", +- "-o", base_name + ".FAKE.so"] ++ "-o", src_base_name + ".FAKE.so"] + run_cmd(cmd) + fake_created[dep] = True + dso_deps = map(lambda d: testpfx + test_name + "-" + d + ".so", +@@ -932,7 +953,7 @@ def process_testcase(t): + main_deps = map(lambda d: testpfx + test_name + "-" + d + ".so", + deps) + cmd = [build_gcc, "-Wl,--no-as-needed", "-o", testpfx + test_name, +- testpfx + test_name + ".c", "-L%s" % (os.getcwd()), ++ testpfx_src + test_name + ".c", "-L%s" % (os.getcwd()), + "-Wl,-rpath-link=%s" % (os.getcwd())] + if '#' in test_descr.soname_map: + soname = ("-Wl,-soname=" + testpfx + test_name + "-" +@@ -987,14 +1008,14 @@ def process_testcase(t): + sfx = "" + if r[0] != "": + sfx = "-" + r[0].replace("=","_") +- f = open(testpfx + t.test_name + sfx + ".exp", "w") ++ f = open(testpfx_src + t.test_name + sfx + ".exp", "w") + (output, xfail) = r[1] + f.write('%s' % output) + f.close() + + # Create header part of top-level testcase shell script, to wrap execution + # and output comparison together. +- t.sh = open(testpfx + t.test_name + ".sh", "w") ++ t.sh = open(testpfx_src + t.test_name + ".sh", "w") + t.sh.write("#!/bin/sh\n") + t.sh.write("# Test driver for %s, generated by " + "dso-ordering-test.py\n" % (t.test_name)) +@@ -1022,12 +1043,12 @@ def process_testcase(t): + sfx = "" + if r[0] != "": + sfx = "-" + r[0].replace("=","_") +- expected_output_files += " $(objpfx)%s/%s%s.exp" % (test_subdir, ++ expected_output_files += " $(objpfx)%s%s%s.exp" % (test_srcdir, + t.test_name, sfx) + makefile.write \ +- ("$(objpfx)%s.out: $(objpfx)%s/%s.sh%s " ++ ("$(objpfx)%s.out: $(objpfx)%s%s.sh%s " + "$(common-objpfx)support/test-run-command\n" +- % (t.test_name, test_subdir, t.test_name, ++ % (t.test_name, test_srcdir, t.test_name, + expected_output_files)) + makefile.write("\t$(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' " + "'$(run-program-env)' > $@; $(evaluate-test)\n") diff --git a/glibc-rh1159809-3.patch b/glibc-rh1159809-3.patch new file mode 100644 index 0000000..fa39efe --- /dev/null +++ b/glibc-rh1159809-3.patch @@ -0,0 +1,589 @@ +commit 15a0c5730d1d5aeb95f50c9ec7470640084feae8 +Author: Chung-Lin Tang +Date: Thu Oct 21 21:41:22 2021 +0800 + + elf: Fix slow DSO sorting behavior in dynamic loader (BZ #17645) + + This second patch contains the actual implementation of a new sorting algorithm + for shared objects in the dynamic loader, which solves the slow behavior that + the current "old" algorithm falls into when the DSO set contains circular + dependencies. + + The new algorithm implemented here is simply depth-first search (DFS) to obtain + the Reverse-Post Order (RPO) sequence, a topological sort. A new l_visited:1 + bitfield is added to struct link_map to more elegantly facilitate such a search. + + The DFS algorithm is applied to the input maps[nmap-1] backwards towards + maps[0]. This has the effect of a more "shallow" recursion depth in general + since the input is in BFS. Also, when combined with the natural order of + processing l_initfini[] at each node, this creates a resulting output sorting + closer to the intuitive "left-to-right" order in most cases. + + Another notable implementation adjustment related to this _dl_sort_maps change + is the removing of two char arrays 'used' and 'done' in _dl_close_worker to + represent two per-map attributes. This has been changed to simply use two new + bit-fields l_map_used:1, l_map_done:1 added to struct link_map. This also allows + discarding the clunky 'used' array sorting that _dl_sort_maps had to sometimes + do along the way. + + Tunable support for switching between different sorting algorithms at runtime is + also added. A new tunable 'glibc.rtld.dynamic_sort' with current valid values 1 + (old algorithm) and 2 (new DFS algorithm) has been added. At time of commit + of this patch, the default setting is 1 (old algorithm). + + Signed-off-by: Chung-Lin Tang + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/dl-tunables.list + (No mem.tagging tunable downstream.) + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 74ca9a85dd309780..22225efb3226c3e1 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -167,8 +167,6 @@ _dl_close_worker (struct link_map *map, bool force) + + bool any_tls = false; + const unsigned int nloaded = ns->_ns_nloaded; +- char used[nloaded]; +- char done[nloaded]; + struct link_map *maps[nloaded]; + + /* Run over the list and assign indexes to the link maps and enter +@@ -176,24 +174,21 @@ _dl_close_worker (struct link_map *map, bool force) + int idx = 0; + for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next) + { ++ l->l_map_used = 0; ++ l->l_map_done = 0; + l->l_idx = idx; + maps[idx] = l; + ++idx; +- + } + assert (idx == nloaded); + +- /* Prepare the bitmaps. */ +- memset (used, '\0', sizeof (used)); +- memset (done, '\0', sizeof (done)); +- + /* Keep track of the lowest index link map we have covered already. */ + int done_index = -1; + while (++done_index < nloaded) + { + struct link_map *l = maps[done_index]; + +- if (done[done_index]) ++ if (l->l_map_done) + /* Already handled. */ + continue; + +@@ -204,12 +199,12 @@ _dl_close_worker (struct link_map *map, bool force) + /* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why + acquire is sufficient and correct. */ + && atomic_load_acquire (&l->l_tls_dtor_count) == 0 +- && !used[done_index]) ++ && !l->l_map_used) + continue; + + /* We need this object and we handle it now. */ +- done[done_index] = 1; +- used[done_index] = 1; ++ l->l_map_used = 1; ++ l->l_map_done = 1; + /* Signal the object is still needed. */ + l->l_idx = IDX_STILL_USED; + +@@ -225,9 +220,9 @@ _dl_close_worker (struct link_map *map, bool force) + { + assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded); + +- if (!used[(*lp)->l_idx]) ++ if (!(*lp)->l_map_used) + { +- used[(*lp)->l_idx] = 1; ++ (*lp)->l_map_used = 1; + /* If we marked a new object as used, and we've + already processed it, then we need to go back + and process again from that point forward to +@@ -250,9 +245,9 @@ _dl_close_worker (struct link_map *map, bool force) + { + assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded); + +- if (!used[jmap->l_idx]) ++ if (!jmap->l_map_used) + { +- used[jmap->l_idx] = 1; ++ jmap->l_map_used = 1; + if (jmap->l_idx - 1 < done_index) + done_index = jmap->l_idx - 1; + } +@@ -262,8 +257,7 @@ _dl_close_worker (struct link_map *map, bool force) + + /* Sort the entries. We can skip looking for the binary itself which is + at the front of the search list for the main namespace. */ +- _dl_sort_maps (maps + (nsid == LM_ID_BASE), nloaded - (nsid == LM_ID_BASE), +- used + (nsid == LM_ID_BASE), true); ++ _dl_sort_maps (maps, nloaded, (nsid == LM_ID_BASE), true); + + /* Call all termination functions at once. */ + bool unload_any = false; +@@ -277,7 +271,7 @@ _dl_close_worker (struct link_map *map, bool force) + /* All elements must be in the same namespace. */ + assert (imap->l_ns == nsid); + +- if (!used[i]) ++ if (!imap->l_map_used) + { + assert (imap->l_type == lt_loaded && !imap->l_nodelete_active); + +@@ -315,7 +309,7 @@ _dl_close_worker (struct link_map *map, bool force) + if (i < first_loaded) + first_loaded = i; + } +- /* Else used[i]. */ ++ /* Else imap->l_map_used. */ + else if (imap->l_type == lt_loaded) + { + struct r_scope_elem *new_list = NULL; +@@ -524,7 +518,7 @@ _dl_close_worker (struct link_map *map, bool force) + for (unsigned int i = first_loaded; i < nloaded; ++i) + { + struct link_map *imap = maps[i]; +- if (!used[i]) ++ if (!imap->l_map_used) + { + assert (imap->l_type == lt_loaded); + +diff --git a/elf/dl-deps.c b/elf/dl-deps.c +index 007069f670eced95..9365d54c8e03e5f4 100644 +--- a/elf/dl-deps.c ++++ b/elf/dl-deps.c +@@ -612,10 +612,9 @@ Filters not supported with LD_TRACE_PRELINKING")); + + /* If libc.so.6 is the main map, it participates in the sort, so + that the relocation order is correct regarding libc.so.6. */ +- if (l_initfini[0] == GL (dl_ns)[l_initfini[0]->l_ns].libc_map) +- _dl_sort_maps (l_initfini, nlist, NULL, false); +- else +- _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false); ++ _dl_sort_maps (l_initfini, nlist, ++ (l_initfini[0] != GL (dl_ns)[l_initfini[0]->l_ns].libc_map), ++ false); + + /* Terminate the list of dependencies. */ + l_initfini[nlist] = NULL; +diff --git a/elf/dl-fini.c b/elf/dl-fini.c +index eea9d8aad736a99e..e14259a3c8806e0d 100644 +--- a/elf/dl-fini.c ++++ b/elf/dl-fini.c +@@ -95,8 +95,7 @@ _dl_fini (void) + /* Now we have to do the sorting. We can skip looking for the + binary itself which is at the front of the search list for + the main namespace. */ +- _dl_sort_maps (maps + (ns == LM_ID_BASE), nmaps - (ns == LM_ID_BASE), +- NULL, true); ++ _dl_sort_maps (maps, nmaps, (ns == LM_ID_BASE), true); + + /* We do not rely on the linked list of loaded object anymore + from this point on. We have our own list here (maps). The +diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c +index b2a01ede627be1e9..398a08f28c4d9ff1 100644 +--- a/elf/dl-sort-maps.c ++++ b/elf/dl-sort-maps.c +@@ -16,16 +16,24 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include ++#include + ++/* Note: this is the older, "original" sorting algorithm, being used as ++ default up to 2.35. + +-/* Sort array MAPS according to dependencies of the contained objects. +- Array USED, if non-NULL, is permutated along MAPS. If FOR_FINI this is +- called for finishing an object. */ +-void +-_dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used, +- bool for_fini) ++ Sort array MAPS according to dependencies of the contained objects. ++ If FOR_FINI is true, this is called for finishing an object. */ ++static void ++_dl_sort_maps_original (struct link_map **maps, unsigned int nmaps, ++ unsigned int skip, bool for_fini) + { ++ /* Allows caller to do the common optimization of skipping the first map, ++ usually the main binary. */ ++ maps += skip; ++ nmaps -= skip; ++ + /* A list of one element need not be sorted. */ + if (nmaps <= 1) + return; +@@ -66,14 +74,6 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used, + (k - i) * sizeof (maps[0])); + maps[k] = thisp; + +- if (used != NULL) +- { +- char here_used = used[i]; +- memmove (&used[i], &used[i + 1], +- (k - i) * sizeof (used[0])); +- used[k] = here_used; +- } +- + if (seen[i + 1] > nmaps - i) + { + ++i; +@@ -120,3 +120,183 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used, + next:; + } + } ++ ++#if !HAVE_TUNABLES ++/* In this case, just default to the original algorithm. */ ++strong_alias (_dl_sort_maps_original, _dl_sort_maps); ++#else ++ ++/* We use a recursive function due to its better clarity and ease of ++ implementation, as well as faster execution speed. We already use ++ alloca() for list allocation during the breadth-first search of ++ dependencies in _dl_map_object_deps(), and this should be on the ++ same order of worst-case stack usage. ++ ++ Note: the '*rpo' parameter is supposed to point to one past the ++ last element of the array where we save the sort results, and is ++ decremented before storing the current map at each level. */ ++ ++static void ++dfs_traversal (struct link_map ***rpo, struct link_map *map, ++ bool *do_reldeps) ++{ ++ if (map->l_visited) ++ return; ++ ++ map->l_visited = 1; ++ ++ if (map->l_initfini) ++ { ++ for (int i = 0; map->l_initfini[i] != NULL; i++) ++ { ++ struct link_map *dep = map->l_initfini[i]; ++ if (dep->l_visited == 0 ++ && dep->l_main_map == 0) ++ dfs_traversal (rpo, dep, do_reldeps); ++ } ++ } ++ ++ if (__glibc_unlikely (do_reldeps != NULL && map->l_reldeps != NULL)) ++ { ++ /* Indicate that we encountered relocation dependencies during ++ traversal. */ ++ *do_reldeps = true; ++ ++ for (int m = map->l_reldeps->act - 1; m >= 0; m--) ++ { ++ struct link_map *dep = map->l_reldeps->list[m]; ++ if (dep->l_visited == 0 ++ && dep->l_main_map == 0) ++ dfs_traversal (rpo, dep, do_reldeps); ++ } ++ } ++ ++ *rpo -= 1; ++ **rpo = map; ++} ++ ++/* Topologically sort array MAPS according to dependencies of the contained ++ objects. */ ++ ++static void ++_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, ++ unsigned int skip __attribute__ ((unused)), bool for_fini) ++{ ++ for (int i = nmaps - 1; i >= 0; i--) ++ maps[i]->l_visited = 0; ++ ++ /* We apply DFS traversal for each of maps[i] until the whole total order ++ is found and we're at the start of the Reverse-Postorder (RPO) sequence, ++ which is a topological sort. ++ ++ We go from maps[nmaps - 1] backwards towards maps[0] at this level. ++ Due to the breadth-first search (BFS) ordering we receive, going ++ backwards usually gives a more shallow depth-first recursion depth, ++ adding more stack usage safety. Also, combined with the natural ++ processing order of l_initfini[] at each node during DFS, this maintains ++ an ordering closer to the original link ordering in the sorting results ++ under most simpler cases. ++ ++ Another reason we order the top level backwards, it that maps[0] is ++ usually exactly the main object of which we're in the midst of ++ _dl_map_object_deps() processing, and maps[0]->l_initfini[] is still ++ blank. If we start the traversal from maps[0], since having no ++ dependencies yet filled in, maps[0] will always be immediately ++ incorrectly placed at the last place in the order (first in reverse). ++ Adjusting the order so that maps[0] is last traversed naturally avoids ++ this problem. ++ ++ Further, the old "optimization" of skipping the main object at maps[0] ++ from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general ++ no longer valid, since traversing along object dependency-links ++ may "find" the main object even when it is not included in the initial ++ order (e.g. a dlopen()'ed shared object can have circular dependencies ++ linked back to itself). In such a case, traversing N-1 objects will ++ create a N-object result, and raise problems. ++ ++ To summarize, just passing in the full list, and iterating from back ++ to front makes things much more straightforward. */ ++ ++ /* Array to hold RPO sorting results, before we copy back to maps[]. */ ++ struct link_map *rpo[nmaps]; ++ ++ /* The 'head' position during each DFS iteration. Note that we start at ++ one past the last element due to first-decrement-then-store (see the ++ bottom of above dfs_traversal() routine). */ ++ struct link_map **rpo_head = &rpo[nmaps]; ++ ++ bool do_reldeps = false; ++ bool *do_reldeps_ref = (for_fini ? &do_reldeps : NULL); ++ ++ for (int i = nmaps - 1; i >= 0; i--) ++ { ++ dfs_traversal (&rpo_head, maps[i], do_reldeps_ref); ++ ++ /* We can break early if all objects are already placed. */ ++ if (rpo_head == rpo) ++ goto end; ++ } ++ assert (rpo_head == rpo); ++ ++ end: ++ /* Here we may do a second pass of sorting, using only l_initfini[] ++ static dependency links. This is avoided if !FOR_FINI or if we didn't ++ find any reldeps in the first DFS traversal. ++ ++ The reason we do this is: while it is unspecified how circular ++ dependencies should be handled, the presumed reasonable behavior is to ++ have destructors to respect static dependency links as much as possible, ++ overriding reldeps if needed. And the first sorting pass, which takes ++ l_initfini/l_reldeps links equally, may not preserve this priority. ++ ++ Hence we do a 2nd sorting pass, taking only DT_NEEDED links into account ++ (see how the do_reldeps argument to dfs_traversal() is NULL below). */ ++ if (do_reldeps) ++ { ++ for (int i = nmaps - 1; i >= 0; i--) ++ rpo[i]->l_visited = 0; ++ ++ struct link_map **maps_head = &maps[nmaps]; ++ for (int i = nmaps - 1; i >= 0; i--) ++ { ++ dfs_traversal (&maps_head, rpo[i], NULL); ++ ++ /* We can break early if all objects are already placed. ++ The below memcpy is not needed in the do_reldeps case here, ++ since we wrote back to maps[] during DFS traversal. */ ++ if (maps_head == maps) ++ return; ++ } ++ assert (maps_head == maps); ++ return; ++ } ++ ++ memcpy (maps, rpo, sizeof (struct link_map *) * nmaps); ++} ++ ++void ++_dl_sort_maps_init (void) ++{ ++ int32_t algorithm = TUNABLE_GET (glibc, rtld, dynamic_sort, int32_t, NULL); ++ GLRO(dl_dso_sort_algo) = algorithm == 1 ? dso_sort_algorithm_original ++ : dso_sort_algorithm_dfs; ++} ++ ++void ++_dl_sort_maps (struct link_map **maps, unsigned int nmaps, ++ unsigned int skip, bool for_fini) ++{ ++ /* It can be tempting to use a static function pointer to store and call ++ the current selected sorting algorithm routine, but experimentation ++ shows that current processors still do not handle indirect branches ++ that efficiently, plus a static function pointer will involve ++ PTR_MANGLE/DEMANGLE, further impairing performance of small, common ++ input cases. A simple if-case with direct function calls appears to ++ be the fastest. */ ++ if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original)) ++ _dl_sort_maps_original (maps, nmaps, skip, for_fini); ++ else ++ _dl_sort_maps_dfs (maps, nmaps, skip, for_fini); ++} ++ ++#endif /* HAVE_TUNABLES. */ +diff --git a/elf/dl-support.c b/elf/dl-support.c +index e9943e889ef447ad..ae03aec9764e29d3 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -155,6 +155,8 @@ size_t _dl_phnum; + uint64_t _dl_hwcap __attribute__ ((nocommon)); + uint64_t _dl_hwcap2 __attribute__ ((nocommon)); + ++enum dso_sort_algorithm _dl_dso_sort_algo; ++ + /* The value of the FPU control word the kernel will preset in hardware. */ + fpu_control_t _dl_fpu_control = _FPU_DEFAULT; + +diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c +index 998c5d52bcab8193..4e8a986541fc4c09 100644 +--- a/elf/dl-sysdep.c ++++ b/elf/dl-sysdep.c +@@ -223,6 +223,9 @@ _dl_sysdep_start (void **start_argptr, + + __tunables_init (_environ); + ++ /* Initialize DSO sorting algorithm after tunables. */ ++ _dl_sort_maps_init (); ++ + #ifdef DL_SYSDEP_INIT + DL_SYSDEP_INIT; + #endif +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index 6408a8e5ae92d2c6..54ef2a921310b229 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -140,4 +140,13 @@ glibc { + default: 512 + } + } ++ ++ rtld { ++ dynamic_sort { ++ type: INT_32 ++ minval: 1 ++ maxval: 2 ++ default: 1 ++ } ++ } + } +diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def +index 873ddf55d91155c6..5f7f18ef270bc12d 100644 +--- a/elf/dso-sort-tests-1.def ++++ b/elf/dso-sort-tests-1.def +@@ -62,5 +62,5 @@ output: b>a>{}b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c +-xfail_output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[l_name = (char *) ""; + *user_entry = main_map->l_entry; + ++ /* Set bit indicating this is the main program map. */ ++ main_map->l_main_map = 1; ++ + #ifdef HAVE_AUX_VECTOR + /* Adjust the on-stack auxiliary vector so that it looks like the + binary was executed directly. */ +diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp +index 4f3f7ee4e30a2b42..118afc271057afd4 100644 +--- a/elf/tst-rtld-list-tunables.exp ++++ b/elf/tst-rtld-list-tunables.exp +@@ -10,5 +10,6 @@ glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0x[f]+) + glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+) + glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0x[f]+) + glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+) ++glibc.rtld.dynamic_sort: 1 (min: 1, max: 2) + glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10) + glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+) +diff --git a/include/link.h b/include/link.h +index dd491989beb41353..041ff5f753a9ee11 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -181,6 +181,11 @@ struct link_map + unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */ + unsigned int l_global:1; /* Nonzero if object in _dl_global_scope. */ + unsigned int l_reserved:2; /* Reserved for internal use. */ ++ unsigned int l_main_map:1; /* Nonzero for the map of the main program. */ ++ unsigned int l_visited:1; /* Used internally for map dependency ++ graph traversal. */ ++ unsigned int l_map_used:1; /* These two bits are used during traversal */ ++ unsigned int l_map_done:1; /* of maps in _dl_close_worker. */ + unsigned int l_phdr_allocated:1; /* Nonzero if the data structure pointed + to by `l_phdr' is allocated. */ + unsigned int l_soname_added:1; /* Nonzero if the SONAME is for sure in +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 43272cf885d1e3e6..c3f96cdc85208926 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -303,6 +303,17 @@ changed once allocated at process startup. The default allocation of + optional static TLS is 512 bytes and is allocated in every thread. + @end deftp + ++@deftp Tunable glibc.rtld.dynamic_sort ++Sets the algorithm to use for DSO sorting, valid values are @samp{1} and ++@samp{2}. For value of @samp{1}, an older O(n^3) algorithm is used, which is ++long time tested, but may have performance issues when dependencies between ++shared objects contain cycles due to circular dependencies. When set to the ++value of @samp{2}, a different algorithm is used, which implements a ++topological sort through depth-first search, and does not exhibit the ++performance issues of @samp{1}. ++ ++The default value of this tunable is @samp{1}. ++@end deftp + + @node Elision Tunables + @section Elision Tunables +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 5e56550a4d556fa7..9f09a4a280396659 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -240,6 +240,13 @@ enum allowmask + }; + + ++/* DSO sort algorithm to use (check dl-sort-maps.c). */ ++enum dso_sort_algorithm ++ { ++ dso_sort_algorithm_original, ++ dso_sort_algorithm_dfs ++ }; ++ + struct audit_ifaces + { + void (*activity) (uintptr_t *, unsigned int); +@@ -633,6 +640,8 @@ struct rtld_global_ro + platforms. */ + EXTERN uint64_t _dl_hwcap2; + ++ EXTERN enum dso_sort_algorithm _dl_dso_sort_algo; ++ + #ifdef SHARED + /* We add a function table to _rtld_global which is then used to + call the function instead of going through the PLT. The result +@@ -1049,7 +1058,7 @@ extern void _dl_fini (void) attribute_hidden; + + /* Sort array MAPS according to dependencies of the contained objects. */ + extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps, +- char *used, bool for_fini) attribute_hidden; ++ unsigned int skip, bool for_fini) attribute_hidden; + + /* The dynamic linker calls this function before and having changing + any shared object mappings. The `r_state' member of `struct r_debug' +@@ -1167,6 +1176,9 @@ extern struct link_map * _dl_get_dl_main_map (void) + # endif + #endif + ++/* Initialize the DSO sort algorithm to use. */ ++extern void _dl_sort_maps_init (void) attribute_hidden; ++ + /* Initialization of libpthread for statically linked applications. + If libpthread is not linked in, this is an empty function. */ + void __pthread_initialize_minimal (void) weak_function; diff --git a/glibc-rh1159809-4.patch b/glibc-rh1159809-4.patch new file mode 100644 index 0000000..e47b934 --- /dev/null +++ b/glibc-rh1159809-4.patch @@ -0,0 +1,25 @@ +commit d3bf2f5927d51258a51ac7fde04f4805f8ee294a +Author: Adhemerval Zanella +Date: Wed Nov 3 09:19:30 2021 -0300 + + elf: Do not run DSO sorting if tunables is not enabled + + Since the argorithm selection requires tunables. + + Checked on x86_64-linux-gnu with --enable-tunables=no. + +diff --git a/elf/Makefile b/elf/Makefile +index e92f62f279566684..3b5e1f59e6696a2b 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -998,8 +998,10 @@ include $(objpfx)$(1).generated-makefile + endef + + # Generate from each testcase description file ++ifeq (yes,$(have-tunables)) + $(eval $(call include_dsosort_tests,dso-sort-tests-1.def)) + $(eval $(call include_dsosort_tests,dso-sort-tests-2.def)) ++endif + + check-abi: $(objpfx)check-abi-ld.out + tests-special += $(objpfx)check-abi-ld.out diff --git a/glibc-rh1159809-5.patch b/glibc-rh1159809-5.patch new file mode 100644 index 0000000..dcd7703 --- /dev/null +++ b/glibc-rh1159809-5.patch @@ -0,0 +1,45 @@ +commit 1f67d8286b5da9266a138198ef1f15c27cbb0010 +Author: H.J. Lu +Date: Mon Nov 15 16:28:39 2021 -0800 + + elf: Use a temporary file to generate Makefile fragments [BZ #28550] + + 1. Use a temporary file to generate Makefile fragments for DSO sorting + tests and use -include on them. + 2. Add Makefile fragments to postclean-generated so that a "make clean" + removes the autogenerated fragments and a subsequent "make" regenerates + them. + + This partially fixes BZ #28550. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index 3b5e1f59e6696a2b..22a8060f7d3bb1a1 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -986,6 +986,7 @@ tests-special += \ + # tests-special + endif + ++ifndef avoid-generated + # DSO sorting tests: + # The dso-ordering-test.py script generates testcase source files in $(objpfx), + # creating a $(objpfx)-dir for each testcase, and creates a +@@ -993,9 +994,14 @@ endif + define include_dsosort_tests + $(objpfx)$(1).generated-makefile: $(1) + $(PYTHON) $(..)scripts/dso-ordering-test.py \ +- --description-file $$< --objpfx $(objpfx) --output-makefile $$@ +-include $(objpfx)$(1).generated-makefile ++ --description-file $$< --objpfx $(objpfx) --output-makefile $$@T ++ mv $$@T $$@ ++-include $(objpfx)$(1).generated-makefile + endef ++endif ++ ++postclean-generated += $(objpfx)/dso-sort-tests-2.generated-makefile \ ++ $(objpfx)/dso-sort-tests-2.generated-makefile + + # Generate from each testcase description file + ifeq (yes,$(have-tunables)) diff --git a/glibc-rh1159809-6.patch b/glibc-rh1159809-6.patch new file mode 100644 index 0000000..df6d0e2 --- /dev/null +++ b/glibc-rh1159809-6.patch @@ -0,0 +1,49 @@ +commit 0884724a95b60452ad483dbe086d237d02ba624d +Author: Florian Weimer +Date: Tue Dec 14 12:37:44 2021 +0100 + + elf: Use new dependency sorting algorithm by default + + The default has to change eventually, and there are no known failures + that require a delay. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index 54ef2a921310b229..f11ca5b3e8b09b43 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -146,7 +146,7 @@ glibc { + type: INT_32 + minval: 1 + maxval: 2 +- default: 1 ++ default: 2 + } + } + } +diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp +index 118afc271057afd4..478ee8ab091685eb 100644 +--- a/elf/tst-rtld-list-tunables.exp ++++ b/elf/tst-rtld-list-tunables.exp +@@ -10,6 +10,6 @@ glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0x[f]+) + glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+) + glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0x[f]+) + glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+) +-glibc.rtld.dynamic_sort: 1 (min: 1, max: 2) ++glibc.rtld.dynamic_sort: 2 (min: 1, max: 2) + glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10) + glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+) +diff --git a/manual/tunables.texi b/manual/tunables.texi +index c3f96cdc85208926..7b70e80391ee87f7 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -312,7 +312,7 @@ value of @samp{2}, a different algorithm is used, which implements a + topological sort through depth-first search, and does not exhibit the + performance issues of @samp{1}. + +-The default value of this tunable is @samp{1}. ++The default value of this tunable is @samp{2}. + @end deftp + + @node Elision Tunables diff --git a/glibc-rh1159809-7.patch b/glibc-rh1159809-7.patch new file mode 100644 index 0000000..c396a5c --- /dev/null +++ b/glibc-rh1159809-7.patch @@ -0,0 +1,357 @@ +commit 3a0588ae48fb35384a6bd33f9b66403badfa1262 +Author: Adhemerval Zanella +Date: Tue Feb 8 15:22:49 2022 -0300 + + elf: Fix DFS sorting algorithm for LD_TRACE_LOADED_OBJECTS with missing libraries (BZ #28868) + + On _dl_map_object the underlying file is not opened in trace mode + (in other cases where the underlying file can't be opened, + _dl_map_object quits with an error). If there any missing libraries + being processed, they will not be considered on final nlist size + passed on _dl_sort_maps later in the function. And it is then used by + _dl_sort_maps_dfs on the stack allocated working maps: + + 222 /* Array to hold RPO sorting results, before we copy back to maps[]. */ + 223 struct link_map *rpo[nmaps]; + 224 + 225 /* The 'head' position during each DFS iteration. Note that we start at + 226 one past the last element due to first-decrement-then-store (see the + 227 bottom of above dfs_traversal() routine). */ + 228 struct link_map **rpo_head = &rpo[nmaps]; + + However while transversing the 'l_initfini' on dfs_traversal it will + still consider the l_faked maps and thus update rpo more times than the + allocated working 'rpo', overflowing the stack object. + + As suggested in bugzilla, one option would be to avoid sorting the maps + for trace mode. However I think ignoring l_faked object does make + sense (there is one less constraint to call the sorting function), it + allows a slight less stack usage for trace, and it is slight simpler + solution. + + The tests does trigger the stack overflow, however I tried to make + it more generic to check different scenarios or missing objects. + + Checked on x86_64-linux-gnu. + + Reviewed-by: Siddhesh Poyarekar + +Conflicts: + elf/Makefile + (differences in backported tests) + +diff --git a/elf/Makefile b/elf/Makefile +index 22a8060f7d3bb1a1..634c3113227d64a6 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -584,6 +584,11 @@ modules-names = \ + libmarkermod5-3 \ + libmarkermod5-4 \ + libmarkermod5-5 \ ++ libtracemod1-1 \ ++ libtracemod2-1 \ ++ libtracemod3-1 \ ++ libtracemod4-1 \ ++ libtracemod5-1 \ + ltglobmod1 \ + ltglobmod2 \ + neededobj1 \ +@@ -983,6 +988,11 @@ tests-special += \ + $(objpfx)tst-initorder2-cmp.out \ + $(objpfx)tst-unused-dep-cmp.out \ + $(objpfx)tst-unused-dep.out \ ++ $(objpfx)tst-trace1.out \ ++ $(objpfx)tst-trace2.out \ ++ $(objpfx)tst-trace3.out \ ++ $(objpfx)tst-trace4.out \ ++ $(objpfx)tst-trace5.out \ + # tests-special + endif + +@@ -2619,6 +2629,51 @@ $(objpfx)tst-rtld-run-static.out: $(objpfx)/ldconfig + + $(objpfx)tst-dlmopen-gethostbyname: $(libdl) + $(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so ++ ++LDFLAGS-libtracemod1-1.so += -Wl,-soname,libtracemod1.so ++LDFLAGS-libtracemod2-1.so += -Wl,-soname,libtracemod2.so ++LDFLAGS-libtracemod3-1.so += -Wl,-soname,libtracemod3.so ++LDFLAGS-libtracemod4-1.so += -Wl,-soname,libtracemod4.so ++LDFLAGS-libtracemod5-1.so += -Wl,-soname,libtracemod5.so ++ ++$(objpfx)libtracemod1-1.so: $(objpfx)libtracemod2-1.so \ ++ $(objpfx)libtracemod3-1.so ++$(objpfx)libtracemod2-1.so: $(objpfx)libtracemod4-1.so \ ++ $(objpfx)libtracemod5-1.so ++ ++define libtracemod-x ++$(objpfx)libtracemod$(1)/libtracemod$(1).so: $(objpfx)libtracemod$(1)-1.so ++ $$(make-target-directory) ++ cp $$< $$@ ++endef ++libtracemod-suffixes = 1 2 3 4 5 ++$(foreach i,$(libtracemod-suffixes), $(eval $(call libtracemod-x,$(i)))) ++ ++define tst-trace-skeleton ++$(objpfx)tst-trace$(1).out: $(objpfx)libtracemod1/libtracemod1.so \ ++ $(objpfx)libtracemod2/libtracemod2.so \ ++ $(objpfx)libtracemod3/libtracemod3.so \ ++ $(objpfx)libtracemod4/libtracemod4.so \ ++ $(objpfx)libtracemod5/libtracemod5.so \ ++ $(..)scripts/tst-ld-trace.py \ ++ tst-trace$(1).exp ++ ${ $(PYTHON) $(..)scripts/tst-ld-trace.py \ ++ "$(test-wrapper-env) $(elf-objpfx)$(rtld-installed-name) \ ++ --library-path $(common-objpfx):$(strip $(2)) \ ++ $(objpfx)libtracemod1/libtracemod1.so" tst-trace$(1).exp \ ++ } > $$@; $$(evaluate-test) ++endef ++ ++$(eval $(call tst-trace-skeleton,1,)) ++$(eval $(call tst-trace-skeleton,2,\ ++ $(objpfx)libtracemod2)) ++$(eval $(call tst-trace-skeleton,3,\ ++ $(objpfx)libtracemod2:$(objpfx)libtracemod3)) ++$(eval $(call tst-trace-skeleton,4,\ ++ $(objpfx)libtracemod2:$(objpfx)libtracemod3:$(objpfx)libtracemod4)) ++$(eval $(call tst-trace-skeleton,5,\ ++ $(objpfx)libtracemod2:$(objpfx)libtracemod3:$(objpfx)libtracemod4:$(objpfx)libtracemod5)) ++ + $(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ + $(objpfx)tst-audit-tlsdesc-mod2.so \ + $(shared-thread-library) +diff --git a/elf/dl-deps.c b/elf/dl-deps.c +index 9365d54c8e03e5f4..9ff589c8562b2dd1 100644 +--- a/elf/dl-deps.c ++++ b/elf/dl-deps.c +@@ -489,6 +489,8 @@ _dl_map_object_deps (struct link_map *map, + + for (nlist = 0, runp = known; runp; runp = runp->next) + { ++ /* _dl_sort_maps ignores l_faked object, so it is safe to not consider ++ them for nlist. */ + if (__builtin_expect (trace_mode, 0) && runp->map->l_faked) + /* This can happen when we trace the loading. */ + --map->l_searchlist.r_nlist; +diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c +index 398a08f28c4d9ff1..99354dc08a010dd3 100644 +--- a/elf/dl-sort-maps.c ++++ b/elf/dl-sort-maps.c +@@ -140,7 +140,9 @@ static void + dfs_traversal (struct link_map ***rpo, struct link_map *map, + bool *do_reldeps) + { +- if (map->l_visited) ++ /* _dl_map_object_deps ignores l_faked objects when calculating the ++ number of maps before calling _dl_sort_maps, ignore them as well. */ ++ if (map->l_visited || map->l_faked) + return; + + map->l_visited = 1; +diff --git a/elf/libtracemod1-1.c b/elf/libtracemod1-1.c +new file mode 100644 +index 0000000000000000..7c89c9a5a40b9668 +--- /dev/null ++++ b/elf/libtracemod1-1.c +@@ -0,0 +1 @@ ++/* Empty */ +diff --git a/elf/libtracemod2-1.c b/elf/libtracemod2-1.c +new file mode 100644 +index 0000000000000000..7c89c9a5a40b9668 +--- /dev/null ++++ b/elf/libtracemod2-1.c +@@ -0,0 +1 @@ ++/* Empty */ +diff --git a/elf/libtracemod3-1.c b/elf/libtracemod3-1.c +new file mode 100644 +index 0000000000000000..7c89c9a5a40b9668 +--- /dev/null ++++ b/elf/libtracemod3-1.c +@@ -0,0 +1 @@ ++/* Empty */ +diff --git a/elf/libtracemod4-1.c b/elf/libtracemod4-1.c +new file mode 100644 +index 0000000000000000..7c89c9a5a40b9668 +--- /dev/null ++++ b/elf/libtracemod4-1.c +@@ -0,0 +1 @@ ++/* Empty */ +diff --git a/elf/libtracemod5-1.c b/elf/libtracemod5-1.c +new file mode 100644 +index 0000000000000000..7c89c9a5a40b9668 +--- /dev/null ++++ b/elf/libtracemod5-1.c +@@ -0,0 +1 @@ ++/* Empty */ +diff --git a/elf/tst-trace1.exp b/elf/tst-trace1.exp +new file mode 100644 +index 0000000000000000..4a6f5211a68fe2c8 +--- /dev/null ++++ b/elf/tst-trace1.exp +@@ -0,0 +1,4 @@ ++ld 1 ++libc 1 ++libtracemod2.so 0 ++libtracemod3.so 0 +diff --git a/elf/tst-trace2.exp b/elf/tst-trace2.exp +new file mode 100644 +index 0000000000000000..e13506e2eb9aeca2 +--- /dev/null ++++ b/elf/tst-trace2.exp +@@ -0,0 +1,6 @@ ++ld 1 ++libc 1 ++libtracemod2.so 1 ++libtracemod3.so 0 ++libtracemod4.so 0 ++libtracemod5.so 0 +diff --git a/elf/tst-trace3.exp b/elf/tst-trace3.exp +new file mode 100644 +index 0000000000000000..e574549d12a53d72 +--- /dev/null ++++ b/elf/tst-trace3.exp +@@ -0,0 +1,6 @@ ++ld 1 ++libc 1 ++libtracemod2.so 1 ++libtracemod3.so 1 ++libtracemod4.so 0 ++libtracemod5.so 0 +diff --git a/elf/tst-trace4.exp b/elf/tst-trace4.exp +new file mode 100644 +index 0000000000000000..31ca97b35bde0009 +--- /dev/null ++++ b/elf/tst-trace4.exp +@@ -0,0 +1,6 @@ ++ld 1 ++libc 1 ++libtracemod2.so 1 ++libtracemod3.so 1 ++libtracemod4.so 1 ++libtracemod5.so 0 +diff --git a/elf/tst-trace5.exp b/elf/tst-trace5.exp +new file mode 100644 +index 0000000000000000..5d7d95372656396f +--- /dev/null ++++ b/elf/tst-trace5.exp +@@ -0,0 +1,6 @@ ++ld 1 ++libc 1 ++libtracemod2.so 1 ++libtracemod3.so 1 ++libtracemod4.so 1 ++libtracemod5.so 1 +diff --git a/scripts/tst-ld-trace.py b/scripts/tst-ld-trace.py +new file mode 100755 +index 0000000000000000..f5a402800377f44b +--- /dev/null ++++ b/scripts/tst-ld-trace.py +@@ -0,0 +1,108 @@ ++#!/usr/bin/python3 ++# Dump the output of LD_TRACE_LOADED_OBJECTS in architecture neutral format. ++# Copyright (C) 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 ++# 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 ++# . ++ ++import argparse ++import os ++import subprocess ++import sys ++ ++try: ++ subprocess.run ++except: ++ class _CompletedProcess: ++ def __init__(self, args, returncode, stdout=None, stderr=None): ++ self.args = args ++ self.returncode = returncode ++ self.stdout = stdout ++ self.stderr = stderr ++ ++ def _run(*popenargs, input=None, timeout=None, check=False, **kwargs): ++ assert(timeout is None) ++ with subprocess.Popen(*popenargs, **kwargs) as process: ++ try: ++ stdout, stderr = process.communicate(input) ++ except: ++ process.kill() ++ process.wait() ++ raise ++ returncode = process.poll() ++ if check and returncode: ++ raise subprocess.CalledProcessError(returncode, popenargs) ++ return _CompletedProcess(popenargs, returncode, stdout, stderr) ++ ++ subprocess.run = _run ++ ++def is_vdso(lib): ++ return lib.startswith('linux-gate') or lib.startswith('linux-vdso') ++ ++ ++def parse_trace(cmd, fref): ++ new_env = os.environ.copy() ++ new_env['LD_TRACE_LOADED_OBJECTS'] = '1' ++ trace_out = subprocess.run(cmd, stdout=subprocess.PIPE, check=True, ++ universal_newlines=True, env=new_env).stdout ++ trace = [] ++ for line in trace_out.splitlines(): ++ line = line.strip() ++ if is_vdso(line): ++ continue ++ fields = line.split('=>' if '=>' in line else ' ') ++ lib = os.path.basename(fields[0].strip()) ++ if lib.startswith('ld'): ++ lib = 'ld' ++ elif lib.startswith('libc'): ++ lib = 'libc' ++ found = 1 if fields[1].strip() != 'not found' else 0 ++ trace += ['{} {}'.format(lib, found)] ++ trace = sorted(trace) ++ ++ reference = sorted(line.replace('\n','') for line in fref.readlines()) ++ ++ ret = 0 if trace == reference else 1 ++ if ret != 0: ++ for i in reference: ++ if i not in trace: ++ print("Only in {}: {}".format(fref.name, i)) ++ for i in trace: ++ if i not in reference: ++ print("Only in trace: {}".format(i)) ++ ++ sys.exit(ret) ++ ++ ++def get_parser(): ++ parser = argparse.ArgumentParser(description=__doc__) ++ parser.add_argument('command', ++ help='comand to run') ++ parser.add_argument('reference', ++ help='reference file to compare') ++ return parser ++ ++ ++def main(argv): ++ parser = get_parser() ++ opts = parser.parse_args(argv) ++ with open(opts.reference, 'r') as fref: ++ # Remove the initial 'env' command. ++ parse_trace(opts.command.split()[1:], fref) ++ ++ ++if __name__ == '__main__': ++ main(sys.argv[1:]) diff --git a/glibc-rh1159809-8.patch b/glibc-rh1159809-8.patch new file mode 100644 index 0000000..4c76782 --- /dev/null +++ b/glibc-rh1159809-8.patch @@ -0,0 +1,36 @@ +commit a2211c76c3b994099fd58a06d6072d7495d699cd +Author: Florian Weimer +Date: Fri Mar 18 18:18:35 2022 +0100 + + scripts/dso-ordering-test.py: Fix C&P error in * callrefs processing + + The elf/dso-sort-tests-src subdirectory is not changed by this commit, + so it seems that the cut-and-paste error was not material. + + Reviewed-by: Adhemerval Zanella + +diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py +index bde0406be9da14fc..ee476c810c76f1b0 100644 +--- a/scripts/dso-ordering-test.py ++++ b/scripts/dso-ordering-test.py +@@ -551,17 +551,17 @@ def process_testcase(t): + if obj in t.deps: + deps = t.deps[obj] + if '*' in deps: +- t.deps[obj].remove('*') ++ deps.remove('*') + t.add_deps([obj], non_dep_tgt_objs) + if obj in t.callrefs: + deps = t.callrefs[obj] + if '*' in deps: +- t.deps[obj].remove('*') ++ deps.remove('*') + t.add_callrefs([obj], non_dep_tgt_objs) + if "#" in t.deps: + deps = t.deps["#"] + if '*' in deps: +- t.deps["#"].remove('*') ++ deps.remove('*') + t.add_deps(["#"], non_dep_tgt_objs) + + # If no main program was specified in dependency description, make a diff --git a/glibc-rh1159809-9.patch b/glibc-rh1159809-9.patch new file mode 100644 index 0000000..b621c3e --- /dev/null +++ b/glibc-rh1159809-9.patch @@ -0,0 +1,37 @@ +commit 183d99737298bb3200f0610fdcd1c7549c8ed560 +Author: Florian Weimer +Date: Tue Sep 6 07:38:10 2022 +0200 + + scripts/dso-ordering-test.py: Generate program run-time dependencies + + The main program needs to depend on all shared objects, even objects + that have link-time dependencies among shared objects. Filtering + out shared objects that already have an link-time dependencies is not + necessary here; make will do this automatically. + + Reviewed-by: Adhemerval Zanella + +diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py +index ee476c810c76f1b0..43b5ec4d920ad6a3 100644 +--- a/scripts/dso-ordering-test.py ++++ b/scripts/dso-ordering-test.py +@@ -707,13 +707,12 @@ def process_testcase(t): + "\t$(compile.c) $(OUTPUT_OPTION)\n") + makefile.write (rule) + +- not_depended_objs = find_objs_not_depended_on(test_descr) +- if not_depended_objs: +- depstr = "" +- for dep in not_depended_objs: +- depstr += (" $(objpfx)" + test_subdir + "/" +- + test_name + "-" + dep + ".so") +- makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr)) ++ # Ensure that all shared objects are built before running the ++ # test, whether there link-time dependencies or not. ++ depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep) ++ for dep in test_descr.objs] ++ makefile.write("$(objpfx){}.out: {}\n".format( ++ base_test_name, " ".join(depobjs))) + + # Add main executable to test-srcs + makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name)) diff --git a/glibc-rh1871383-1.patch b/glibc-rh1871383-1.patch new file mode 100644 index 0000000..67c88fd --- /dev/null +++ b/glibc-rh1871383-1.patch @@ -0,0 +1,245 @@ +From a1a486d70ebcc47a686ff5846875eacad0940e41 Mon Sep 17 00:00:00 2001 +From: Eyal Itkin +Date: Fri, 20 Mar 2020 21:19:17 +0200 +Subject: Add Safe-Linking to fastbins and tcache + +Safe-Linking is a security mechanism that protects single-linked +lists (such as the fastbin and tcache) from being tampered by attackers. +The mechanism makes use of randomness from ASLR (mmap_base), and when +combined with chunk alignment integrity checks, it protects the "next" +pointers from being hijacked by an attacker. + +While Safe-Unlinking protects double-linked lists (such as the small +bins), there wasn't any similar protection for attacks against +single-linked lists. This solution protects against 3 common attacks: + * Partial pointer override: modifies the lower bytes (Little Endian) + * Full pointer override: hijacks the pointer to an attacker's location + * Unaligned chunks: pointing the list to an unaligned address + +The design assumes an attacker doesn't know where the heap is located, +and uses the ASLR randomness to "sign" the single-linked pointers. We +mark the pointer as P and the location in which it is stored as L, and +the calculation will be: + * PROTECT(P) := (L >> PAGE_SHIFT) XOR (P) + * *L = PROTECT(P) + +This way, the random bits from the address L (which start at the bit +in the PAGE_SHIFT position), will be merged with LSB of the stored +protected pointer. This protection layer prevents an attacker from +modifying the pointer into a controlled value. + +An additional check that the chunks are MALLOC_ALIGNed adds an +important layer: + * Attackers can't point to illegal (unaligned) memory addresses + * Attackers must guess correctly the alignment bits + +On standard 32 bit Linux machines, an attack will directly fail 7 +out of 8 times, and on 64 bit machines it will fail 15 out of 16 +times. + +This proposed patch was benchmarked and it's effect on the overall +performance of the heap was negligible and couldn't be distinguished +from the default variance between tests on the vanilla version. A +similar protection was added to Chromium's version of TCMalloc +in 2012, and according to their documentation it had an overhead of +less than 2%. + +Reviewed-by: DJ Delorie +Reviewed-by: Carlos O'Donell +Reviewed-by: Adhemerval Zacnella + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index f7cd29bc2f..1282863681 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -327,6 +327,18 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line, + # define MAX_TCACHE_COUNT UINT16_MAX + #endif + ++/* Safe-Linking: ++ Use randomness from ASLR (mmap_base) to protect single-linked lists ++ of Fast-Bins and TCache. That is, mask the "next" pointers of the ++ lists' chunks, and also perform allocation alignment checks on them. ++ This mechanism reduces the risk of pointer hijacking, as was done with ++ Safe-Unlinking in the double-linked lists of Small-Bins. ++ It assumes a minimum page size of 4096 bytes (12 bits). Systems with ++ larger pages provide less entropy, although the pointer mangling ++ still works. */ ++#define PROTECT_PTR(pos, ptr) \ ++ ((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr))) ++#define REVEAL_PTR(ptr) PROTECT_PTR (&ptr, ptr) + + /* + REALLOC_ZERO_BYTES_FREES should be set if a call to +@@ -2157,12 +2169,15 @@ do_check_malloc_state (mstate av) + + while (p != 0) + { ++ if (__glibc_unlikely (!aligned_OK (p))) ++ malloc_printerr ("do_check_malloc_state(): " \ ++ "unaligned fastbin chunk detected"); + /* each chunk claims to be inuse */ + do_check_inuse_chunk (av, p); + total += chunksize (p); + /* chunk belongs in this bin */ + assert (fastbin_index (chunksize (p)) == i); +- p = p->fd; ++ p = REVEAL_PTR (p->fd); + } + } + +@@ -2923,7 +2938,7 @@ tcache_put (mchunkptr chunk, size_t tc_idx) + detect a double free. */ + e->key = tcache; + +- e->next = tcache->entries[tc_idx]; ++ e->next = PROTECT_PTR (&e->next, tcache->entries[tc_idx]); + tcache->entries[tc_idx] = e; + ++(tcache->counts[tc_idx]); + } +@@ -2934,9 +2949,11 @@ static __always_inline void * + tcache_get (size_t tc_idx) + { + tcache_entry *e = tcache->entries[tc_idx]; +- tcache->entries[tc_idx] = e->next; ++ tcache->entries[tc_idx] = REVEAL_PTR (e->next); + --(tcache->counts[tc_idx]); + e->key = NULL; ++ if (__glibc_unlikely (!aligned_OK (e))) ++ malloc_printerr ("malloc(): unaligned tcache chunk detected"); + return (void *) e; + } + +@@ -2960,7 +2977,10 @@ tcache_thread_shutdown (void) + while (tcache_tmp->entries[i]) + { + tcache_entry *e = tcache_tmp->entries[i]; +- tcache_tmp->entries[i] = e->next; ++ if (__glibc_unlikely (!aligned_OK (e))) ++ malloc_printerr ("tcache_thread_shutdown(): " \ ++ "unaligned tcache chunk detected"); ++ tcache_tmp->entries[i] = REVEAL_PTR (e->next); + __libc_free (e); + } + } +@@ -3570,8 +3590,11 @@ _int_malloc (mstate av, size_t bytes) + victim = pp; \ + if (victim == NULL) \ + break; \ ++ pp = REVEAL_PTR (victim->fd); \ ++ if (__glibc_unlikely (!aligned_OK (pp))) \ ++ malloc_printerr ("malloc(): unaligned fastbin chunk detected"); \ + } \ +- while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim)) \ ++ while ((pp = catomic_compare_and_exchange_val_acq (fb, pp, victim)) \ + != victim); \ + + if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ())) +@@ -3583,8 +3606,11 @@ _int_malloc (mstate av, size_t bytes) + + if (victim != NULL) + { ++ if (__glibc_unlikely (!aligned_OK (victim))) ++ malloc_printerr ("malloc(): unaligned fastbin chunk detected"); ++ + if (SINGLE_THREAD_P) +- *fb = victim->fd; ++ *fb = REVEAL_PTR (victim->fd); + else + REMOVE_FB (fb, pp, victim); + if (__glibc_likely (victim != NULL)) +@@ -3605,8 +3631,10 @@ _int_malloc (mstate av, size_t bytes) + while (tcache->counts[tc_idx] < mp_.tcache_count + && (tc_victim = *fb) != NULL) + { ++ if (__glibc_unlikely (!aligned_OK (tc_victim))) ++ malloc_printerr ("malloc(): unaligned fastbin chunk detected"); + if (SINGLE_THREAD_P) +- *fb = tc_victim->fd; ++ *fb = REVEAL_PTR (tc_victim->fd); + else + { + REMOVE_FB (fb, pp, tc_victim); +@@ -4196,11 +4224,15 @@ _int_free (mstate av, mchunkptr p, int have_lock) + LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); + for (tmp = tcache->entries[tc_idx]; + tmp; +- tmp = tmp->next) ++ tmp = REVEAL_PTR (tmp->next)) ++ { ++ if (__glibc_unlikely (!aligned_OK (tmp))) ++ malloc_printerr ("free(): unaligned chunk detected in tcache 2"); + if (tmp == e) + malloc_printerr ("free(): double free detected in tcache 2"); + /* If we get here, it was a coincidence. We've wasted a + few cycles, but don't abort. */ ++ } + } + + if (tcache->counts[tc_idx] < mp_.tcache_count) +@@ -4264,7 +4296,7 @@ _int_free (mstate av, mchunkptr p, int have_lock) + add (i.e., double free). */ + if (__builtin_expect (old == p, 0)) + malloc_printerr ("double free or corruption (fasttop)"); +- p->fd = old; ++ p->fd = PROTECT_PTR (&p->fd, old); + *fb = p; + } + else +@@ -4274,7 +4306,8 @@ _int_free (mstate av, mchunkptr p, int have_lock) + add (i.e., double free). */ + if (__builtin_expect (old == p, 0)) + malloc_printerr ("double free or corruption (fasttop)"); +- p->fd = old2 = old; ++ old2 = old; ++ p->fd = PROTECT_PTR (&p->fd, old); + } + while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) + != old2); +@@ -4472,13 +4505,17 @@ static void malloc_consolidate(mstate av) + if (p != 0) { + do { + { ++ if (__glibc_unlikely (!aligned_OK (p))) ++ malloc_printerr ("malloc_consolidate(): " \ ++ "unaligned fastbin chunk detected"); ++ + unsigned int idx = fastbin_index (chunksize (p)); + if ((&fastbin (av, idx)) != fb) + malloc_printerr ("malloc_consolidate(): invalid chunk size"); + } + + check_inuse_chunk(av, p); +- nextp = p->fd; ++ nextp = REVEAL_PTR (p->fd); + + /* Slightly streamlined version of consolidation code in free() */ + size = chunksize (p); +@@ -4896,8 +4933,13 @@ int_mallinfo (mstate av, struct mallinfo *m) + + for (i = 0; i < NFASTBINS; ++i) + { +- for (p = fastbin (av, i); p != 0; p = p->fd) ++ for (p = fastbin (av, i); ++ p != 0; ++ p = REVEAL_PTR (p->fd)) + { ++ if (__glibc_unlikely (!aligned_OK (p))) ++ malloc_printerr ("int_mallinfo(): " \ ++ "unaligned fastbin chunk detected"); + ++nfastblocks; + fastavail += chunksize (p); + } +@@ -5437,8 +5479,11 @@ __malloc_info (int options, FILE *fp) + + while (p != NULL) + { ++ if (__glibc_unlikely (!aligned_OK (p))) ++ malloc_printerr ("__malloc_info(): " \ ++ "unaligned fastbin chunk detected"); + ++nthissize; +- p = p->fd; ++ p = REVEAL_PTR (p->fd); + } + + fastavail += nthissize * thissize; diff --git a/glibc-rh1871383-2.patch b/glibc-rh1871383-2.patch new file mode 100644 index 0000000..0313dbb --- /dev/null +++ b/glibc-rh1871383-2.patch @@ -0,0 +1,87 @@ +From 768358b6a80742f6be68ecd9f952f4b60614df96 Mon Sep 17 00:00:00 2001 +From: Eyal Itkin +Date: Tue, 31 Mar 2020 01:55:13 -0400 +Subject: Typo fixes and CR cleanup in Safe-Linking + +Removed unneeded '\' chars from end of lines and fixed some +indentation issues that were introduced in the original +Safe-Linking patch. + +Reviewed-by: Carlos O'Donell + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 1282863681..0e4acb22f6 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2170,7 +2170,7 @@ do_check_malloc_state (mstate av) + while (p != 0) + { + if (__glibc_unlikely (!aligned_OK (p))) +- malloc_printerr ("do_check_malloc_state(): " \ ++ malloc_printerr ("do_check_malloc_state(): " + "unaligned fastbin chunk detected"); + /* each chunk claims to be inuse */ + do_check_inuse_chunk (av, p); +@@ -2977,9 +2977,9 @@ tcache_thread_shutdown (void) + while (tcache_tmp->entries[i]) + { + tcache_entry *e = tcache_tmp->entries[i]; +- if (__glibc_unlikely (!aligned_OK (e))) +- malloc_printerr ("tcache_thread_shutdown(): " \ +- "unaligned tcache chunk detected"); ++ if (__glibc_unlikely (!aligned_OK (e))) ++ malloc_printerr ("tcache_thread_shutdown(): " ++ "unaligned tcache chunk detected"); + tcache_tmp->entries[i] = REVEAL_PTR (e->next); + __libc_free (e); + } +@@ -4225,14 +4225,14 @@ _int_free (mstate av, mchunkptr p, int have_lock) + for (tmp = tcache->entries[tc_idx]; + tmp; + tmp = REVEAL_PTR (tmp->next)) +- { +- if (__glibc_unlikely (!aligned_OK (tmp))) +- malloc_printerr ("free(): unaligned chunk detected in tcache 2"); +- if (tmp == e) +- malloc_printerr ("free(): double free detected in tcache 2"); +- /* If we get here, it was a coincidence. We've wasted a +- few cycles, but don't abort. */ +- } ++ { ++ if (__glibc_unlikely (!aligned_OK (tmp))) ++ malloc_printerr ("free(): unaligned chunk detected in tcache 2"); ++ if (tmp == e) ++ malloc_printerr ("free(): double free detected in tcache 2"); ++ /* If we get here, it was a coincidence. We've wasted a ++ few cycles, but don't abort. */ ++ } + } + + if (tcache->counts[tc_idx] < mp_.tcache_count) +@@ -4506,7 +4506,7 @@ static void malloc_consolidate(mstate av) + do { + { + if (__glibc_unlikely (!aligned_OK (p))) +- malloc_printerr ("malloc_consolidate(): " \ ++ malloc_printerr ("malloc_consolidate(): " + "unaligned fastbin chunk detected"); + + unsigned int idx = fastbin_index (chunksize (p)); +@@ -4938,7 +4938,7 @@ int_mallinfo (mstate av, struct mallinfo *m) + p = REVEAL_PTR (p->fd)) + { + if (__glibc_unlikely (!aligned_OK (p))) +- malloc_printerr ("int_mallinfo(): " \ ++ malloc_printerr ("int_mallinfo(): " + "unaligned fastbin chunk detected"); + ++nfastblocks; + fastavail += chunksize (p); +@@ -5480,7 +5480,7 @@ __malloc_info (int options, FILE *fp) + while (p != NULL) + { + if (__glibc_unlikely (!aligned_OK (p))) +- malloc_printerr ("__malloc_info(): " \ ++ malloc_printerr ("__malloc_info(): " + "unaligned fastbin chunk detected"); + ++nthissize; + p = REVEAL_PTR (p->fd); diff --git a/glibc-rh1871383-3.patch b/glibc-rh1871383-3.patch new file mode 100644 index 0000000..e5a18e8 --- /dev/null +++ b/glibc-rh1871383-3.patch @@ -0,0 +1,100 @@ +From 49c3c37651e2d2ec4ff8ce21252bbbc08a9d6639 Mon Sep 17 00:00:00 2001 +From: Eyal Itkin +Date: Tue, 31 Mar 2020 02:00:14 -0400 +Subject: Fix alignment bug in Safe-Linking + +Alignment checks should be performed on the user's buffer and NOT +on the mchunkptr as was done before. This caused bugs in 32 bit +versions, because: 2*sizeof(t) != MALLOC_ALIGNMENT. + +As the tcache works on users' buffers it uses the aligned_OK() +check, and the rest work on mchunkptr and therefore check using +misaligned_chunk(). + +Reviewed-by: Carlos O'Donell + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 0e4acb22f6..6acb5ad43a 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2169,7 +2169,7 @@ do_check_malloc_state (mstate av) + + while (p != 0) + { +- if (__glibc_unlikely (!aligned_OK (p))) ++ if (__glibc_unlikely (misaligned_chunk (p))) + malloc_printerr ("do_check_malloc_state(): " + "unaligned fastbin chunk detected"); + /* each chunk claims to be inuse */ +@@ -2949,11 +2949,11 @@ static __always_inline void * + tcache_get (size_t tc_idx) + { + tcache_entry *e = tcache->entries[tc_idx]; ++ if (__glibc_unlikely (!aligned_OK (e))) ++ malloc_printerr ("malloc(): unaligned tcache chunk detected"); + tcache->entries[tc_idx] = REVEAL_PTR (e->next); + --(tcache->counts[tc_idx]); + e->key = NULL; +- if (__glibc_unlikely (!aligned_OK (e))) +- malloc_printerr ("malloc(): unaligned tcache chunk detected"); + return (void *) e; + } + +@@ -3591,7 +3591,7 @@ _int_malloc (mstate av, size_t bytes) + if (victim == NULL) \ + break; \ + pp = REVEAL_PTR (victim->fd); \ +- if (__glibc_unlikely (!aligned_OK (pp))) \ ++ if (__glibc_unlikely (pp != NULL && misaligned_chunk (pp))) \ + malloc_printerr ("malloc(): unaligned fastbin chunk detected"); \ + } \ + while ((pp = catomic_compare_and_exchange_val_acq (fb, pp, victim)) \ +@@ -3606,8 +3606,8 @@ _int_malloc (mstate av, size_t bytes) + + if (victim != NULL) + { +- if (__glibc_unlikely (!aligned_OK (victim))) +- malloc_printerr ("malloc(): unaligned fastbin chunk detected"); ++ if (__glibc_unlikely (misaligned_chunk (victim))) ++ malloc_printerr ("malloc(): unaligned fastbin chunk detected 2"); + + if (SINGLE_THREAD_P) + *fb = REVEAL_PTR (victim->fd); +@@ -3631,8 +3631,8 @@ _int_malloc (mstate av, size_t bytes) + while (tcache->counts[tc_idx] < mp_.tcache_count + && (tc_victim = *fb) != NULL) + { +- if (__glibc_unlikely (!aligned_OK (tc_victim))) +- malloc_printerr ("malloc(): unaligned fastbin chunk detected"); ++ if (__glibc_unlikely (misaligned_chunk (tc_victim))) ++ malloc_printerr ("malloc(): unaligned fastbin chunk detected 3"); + if (SINGLE_THREAD_P) + *fb = REVEAL_PTR (tc_victim->fd); + else +@@ -4505,7 +4505,7 @@ static void malloc_consolidate(mstate av) + if (p != 0) { + do { + { +- if (__glibc_unlikely (!aligned_OK (p))) ++ if (__glibc_unlikely (misaligned_chunk (p))) + malloc_printerr ("malloc_consolidate(): " + "unaligned fastbin chunk detected"); + +@@ -4937,7 +4937,7 @@ int_mallinfo (mstate av, struct mallinfo *m) + p != 0; + p = REVEAL_PTR (p->fd)) + { +- if (__glibc_unlikely (!aligned_OK (p))) ++ if (__glibc_unlikely (misaligned_chunk (p))) + malloc_printerr ("int_mallinfo(): " + "unaligned fastbin chunk detected"); + ++nfastblocks; +@@ -5479,7 +5479,7 @@ __malloc_info (int options, FILE *fp) + + while (p != NULL) + { +- if (__glibc_unlikely (!aligned_OK (p))) ++ if (__glibc_unlikely (misaligned_chunk (p))) + malloc_printerr ("__malloc_info(): " + "unaligned fastbin chunk detected"); + ++nthissize; diff --git a/glibc-rh1871383-4.patch b/glibc-rh1871383-4.patch new file mode 100644 index 0000000..cac8349 --- /dev/null +++ b/glibc-rh1871383-4.patch @@ -0,0 +1,215 @@ +From 6310d570bf20348135d09e1f9de84a9ae7d06f83 Mon Sep 17 00:00:00 2001 +From: Eyal Itkin +Date: Thu, 2 Apr 2020 07:26:35 -0400 +Subject: Add tests for Safe-Linking + +Adding the test "tst-safe-linking" for testing that Safe-Linking works +as expected. The test checks these 3 main flows: + * tcache protection + * fastbin protection + * malloc_consolidate() correctness + +As there is a random chance of 1/16 that of the alignment will remain +correct, the test checks each flow up to 10 times, using different random +values for the pointer corruption. As a result, the chance for a false +failure of a given tested flow is 2**(-40), thus highly unlikely. + +Reviewed-by: Carlos O'Donell + +diff --git a/malloc/Makefile b/malloc/Makefile +index 984045b5b9..e22cbde22d 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -39,6 +39,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ + tst-malloc-too-large \ + tst-malloc-stats-cancellation \ + tst-tcfree1 tst-tcfree2 tst-tcfree3 \ ++ tst-safe-linking \ + + tests-static := \ + tst-interpose-static-nothread \ +diff --git a/malloc/tst-safe-linking.c b/malloc/tst-safe-linking.c +new file mode 100644 +index 0000000000..067b6c09cf +--- /dev/null ++++ b/malloc/tst-safe-linking.c +@@ -0,0 +1,179 @@ ++/* Test reporting of Safe-Linking caught errors. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Run CALLBACK and check that the data on standard error equals ++ EXPECTED. */ ++static void ++check (const char *test, void (*callback) (void *), ++ const char *expected) ++{ ++ int i, rand_mask; ++ bool success = false; ++ /* There is a chance of 1/16 that a corrupted pointer will be aligned. ++ Try multiple times so that statistical failure will be improbable. */ ++ for (i = 0; i < 10 && !success; ++i) ++ { ++ rand_mask = rand () & 0xFF; ++ struct support_capture_subprocess result ++ = support_capture_subprocess (callback, &rand_mask); ++ /* Did not crash, could happen. Try again. */ ++ if (strlen (result.err.buffer) == 0) ++ continue; ++ /* Crashed, must be the expected result. */ ++ if (strcmp (result.err.buffer, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: test %s unexpected standard error data\n" ++ " expected: %s\n" ++ " actual: %s\n", ++ test, expected, result.err.buffer); ++ } ++ TEST_VERIFY (WIFSIGNALED (result.status)); ++ if (WIFSIGNALED (result.status)) ++ TEST_VERIFY (WTERMSIG (result.status) == SIGABRT); ++ support_capture_subprocess_free (&result); ++ success = true; ++ } ++ TEST_VERIFY (success); ++} ++ ++/* Implementation details must be kept in sync with malloc. */ ++#define TCACHE_FILL_COUNT 7 ++#define TCACHE_ALLOC_SIZE 0x20 ++#define MALLOC_CONSOLIDATE_SIZE 256*1024 ++ ++/* Try corrupting the tcache list. */ ++static void ++test_tcache (void *closure) ++{ ++ int mask = ((int *)closure)[0]; ++ size_t size = TCACHE_ALLOC_SIZE; ++ ++ /* Populate the tcache list. */ ++ void * volatile a = malloc (size); ++ void * volatile b = malloc (size); ++ void * volatile c = malloc (size); ++ free (a); ++ free (b); ++ free (c); ++ ++ /* Corrupt the pointer with a random value, and avoid optimizations. */ ++ printf ("Before: c=%p, c[0]=%p\n", c, ((void **)c)[0]); ++ memset (c, mask & 0xFF, size); ++ printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]); ++ ++ c = malloc (size); ++ /* This line will trigger the Safe-Linking check. */ ++ b = malloc (size); ++ printf ("b=%p\n", b); ++} ++ ++/* Try corrupting the fastbin list. */ ++static void ++test_fastbin (void *closure) ++{ ++ int i; ++ int mask = ((int *)closure)[0]; ++ size_t size = TCACHE_ALLOC_SIZE; ++ ++ /* Take the tcache out of the game. */ ++ for (i = 0; i < TCACHE_FILL_COUNT; ++i) ++ { ++ void * volatile p = calloc (1, size); ++ free (p); ++ } ++ ++ /* Populate the fastbin list. */ ++ void * volatile a = calloc (1, size); ++ void * volatile b = calloc (1, size); ++ void * volatile c = calloc (1, size); ++ free (a); ++ free (b); ++ free (c); ++ ++ /* Corrupt the pointer with a random value, and avoid optimizations. */ ++ printf ("Before: c=%p, c[0]=%p\n", c, ((void **)c)[0]); ++ memset (c, mask & 0xFF, size); ++ printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]); ++ ++ c = calloc (1, size); ++ /* This line will trigger the Safe-Linking check. */ ++ b = calloc (1, size); ++ printf ("b=%p\n", b); ++} ++ ++/* Try corrupting the fastbin list and trigger a consolidate. */ ++static void ++test_fastbin_consolidate (void *closure) ++{ ++ int i; ++ int mask = ((int*)closure)[0]; ++ size_t size = TCACHE_ALLOC_SIZE; ++ ++ /* Take the tcache out of the game. */ ++ for (i = 0; i < TCACHE_FILL_COUNT; ++i) ++ { ++ void * volatile p = calloc (1, size); ++ free (p); ++ } ++ ++ /* Populate the fastbin list. */ ++ void * volatile a = calloc (1, size); ++ void * volatile b = calloc (1, size); ++ void * volatile c = calloc (1, size); ++ free (a); ++ free (b); ++ free (c); ++ ++ /* Corrupt the pointer with a random value, and avoid optimizations. */ ++ printf ("Before: c=%p, c[0]=%p\n", c, ((void **)c)[0]); ++ memset (c, mask & 0xFF, size); ++ printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]); ++ ++ /* This line will trigger the Safe-Linking check. */ ++ b = malloc (MALLOC_CONSOLIDATE_SIZE); ++ printf ("b=%p\n", b); ++} ++ ++static int ++do_test (void) ++{ ++ /* Seed the random for the test. */ ++ srand (time (NULL)); ++ ++ check ("test_tcache", test_tcache, ++ "malloc(): unaligned tcache chunk detected\n"); ++ check ("test_fastbin", test_fastbin, ++ "malloc(): unaligned fastbin chunk detected 2\n"); ++ check ("test_fastbin_consolidate", test_fastbin_consolidate, ++ "malloc_consolidate(): unaligned fastbin chunk detected\n"); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-rh1871383-5.patch b/glibc-rh1871383-5.patch new file mode 100644 index 0000000..bc51a1e --- /dev/null +++ b/glibc-rh1871383-5.patch @@ -0,0 +1,35 @@ +From b9cde4e3aa1ff338da7064daf1386b2f4a7351ba Mon Sep 17 00:00:00 2001 +From: DJ Delorie +Date: Sat, 4 Apr 2020 01:44:56 -0400 +Subject: malloc: ensure set_max_fast never stores zero [BZ #25733] + +The code for set_max_fast() stores an "impossibly small value" +instead of zero, when the parameter is zero. However, for +small values of the parameter (ex: 1 or 2) the computation +results in a zero being stored anyway. + +This patch checks for the parameter being small enough for the +computation to result in zero instead, so that a zero is never +stored. + +key values which result in zero being stored: + +x86-64: 1..7 (or other 64-bit) +i686: 1..11 +armhfp: 1..3 (or other 32-bit) + +Reviewed-by: Carlos O'Donell + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 6acb5ad43a..ee87ddbbf9 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -1632,7 +1632,7 @@ static INTERNAL_SIZE_T global_max_fast; + */ + + #define set_max_fast(s) \ +- global_max_fast = (((s) == 0) \ ++ global_max_fast = (((size_t) (s) <= MALLOC_ALIGN_MASK - SIZE_SZ) \ + ? MIN_CHUNK_SIZE / 2 : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK)) + + static inline INTERNAL_SIZE_T diff --git a/glibc-rh1871383-6.patch b/glibc-rh1871383-6.patch new file mode 100644 index 0000000..b21971a --- /dev/null +++ b/glibc-rh1871383-6.patch @@ -0,0 +1,35 @@ +From 0e00b35704e67c499c3abfbd5b6224a13d38b012 Mon Sep 17 00:00:00 2001 +From: "W. Hashimoto" +Date: Fri, 11 Dec 2020 16:59:10 -0500 +Subject: malloc: Detect infinite-loop in _int_free when freeing tcache + [BZ#27052] + +If linked-list of tcache contains a loop, it invokes infinite +loop in _int_free when freeing tcache. The PoC which invokes +such infinite loop is on the Bugzilla(#27052). This loop +should terminate when the loop exceeds mp_.tcache_count and +the program should abort. The affected glibc version is +2.29 or later. + +Reviewed-by: DJ Delorie + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 5b87bdb081..ec2d934595 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -4224,11 +4224,14 @@ _int_free (mstate av, mchunkptr p, int have_lock) + if (__glibc_unlikely (e->key == tcache)) + { + tcache_entry *tmp; ++ size_t cnt = 0; + LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); + for (tmp = tcache->entries[tc_idx]; + tmp; +- tmp = REVEAL_PTR (tmp->next)) ++ tmp = REVEAL_PTR (tmp->next), ++cnt) + { ++ if (cnt >= mp_.tcache_count) ++ malloc_printerr ("free(): too many chunks detected in tcache"); + if (__glibc_unlikely (!aligned_OK (tmp))) + malloc_printerr ("free(): unaligned chunk detected in tcache 2"); + if (tmp == e) diff --git a/glibc-rh1871383-7.patch b/glibc-rh1871383-7.patch new file mode 100644 index 0000000..61d11c4 --- /dev/null +++ b/glibc-rh1871383-7.patch @@ -0,0 +1,133 @@ +From fc859c304898a5ec72e0ba5269ed136ed0ea10e1 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Wed, 7 Jul 2021 23:02:46 +0530 +Subject: Harden tcache double-free check + +The tcache allocator layer uses the tcache pointer as a key to +identify a block that may be freed twice. Since this is in the +application data area, an attacker exploiting a use-after-free could +potentially get access to the entire tcache structure through this +key. A detailed write-up was provided by Awarau here: + +https://awaraucom.wordpress.com/2020/07/19/house-of-io-remastered/ + +Replace this static pointer use for key checking with one that is +generated at malloc initialization. The first attempt is through +getrandom with a fallback to random_bits(), which is a simple +pseudo-random number generator based on the clock. The fallback ought +to be sufficient since the goal of the randomness is only to make the +key arbitrary enough that it is very unlikely to collide with user +data. + +Co-authored-by: Eyal Itkin + +[note: context for arena.c chunk #2 changed to accomodate missing +tagging support code - DJ] + +diff -rup a/malloc/arena.c b/malloc/arena.c +--- a/malloc/arena.c 2022-09-16 01:09:02.003843024 -0400 ++++ b/malloc/arena.c 2022-09-16 01:25:51.879994057 -0400 +@@ -286,6 +286,10 @@ extern struct dl_open_hook *_dl_open_hoo + libc_hidden_proto (_dl_open_hook); + #endif + ++#if USE_TCACHE ++static void tcache_key_initialize (void); ++#endif ++ + static void + ptmalloc_init (void) + { +@@ -294,6 +298,10 @@ ptmalloc_init (void) + + __malloc_initialized = 0; + ++#if USE_TCACHE ++ tcache_key_initialize (); ++#endif ++ + #ifdef SHARED + /* In case this libc copy is in a non-default namespace, never use brk. + Likewise if dlopened from statically linked program. */ +diff -rup a/malloc/malloc.c b/malloc/malloc.c +--- a/malloc/malloc.c 2022-09-16 01:09:05.491977387 -0400 ++++ b/malloc/malloc.c 2022-09-16 01:25:51.883994213 -0400 +@@ -247,6 +247,10 @@ + /* For SINGLE_THREAD_P. */ + #include + ++/* For tcache double-free check. */ ++#include ++#include ++ + /* + Debugging: + +@@ -2924,7 +2928,7 @@ typedef struct tcache_entry + { + struct tcache_entry *next; + /* This field exists to detect double frees. */ +- struct tcache_perthread_struct *key; ++ uintptr_t key; + } tcache_entry; + + /* There is one of these for each thread, which contains the +@@ -2941,6 +2945,31 @@ typedef struct tcache_perthread_struct + static __thread bool tcache_shutting_down = false; + static __thread tcache_perthread_struct *tcache = NULL; + ++/* Process-wide key to try and catch a double-free in the same thread. */ ++static uintptr_t tcache_key; ++ ++/* The value of tcache_key does not really have to be a cryptographically ++ secure random number. It only needs to be arbitrary enough so that it does ++ not collide with values present in applications. If a collision does happen ++ consistently enough, it could cause a degradation in performance since the ++ entire list is checked to check if the block indeed has been freed the ++ second time. The odds of this happening are exceedingly low though, about 1 ++ in 2^wordsize. There is probably a higher chance of the performance ++ degradation being due to a double free where the first free happened in a ++ different thread; that's a case this check does not cover. */ ++static void ++tcache_key_initialize (void) ++{ ++ if (__getrandom (&tcache_key, sizeof(tcache_key), GRND_NONBLOCK) ++ != sizeof (tcache_key)) ++ { ++ tcache_key = random_bits (); ++#if __WORDSIZE == 64 ++ tcache_key = (tcache_key << 32) | random_bits (); ++#endif ++ } ++} ++ + /* Caller must ensure that we know tc_idx is valid and there's room + for more chunks. */ + static __always_inline void +@@ -2950,7 +2979,7 @@ tcache_put (mchunkptr chunk, size_t tc_i + + /* Mark this chunk as "in the tcache" so the test in _int_free will + detect a double free. */ +- e->key = tcache; ++ e->key = tcache_key; + + e->next = PROTECT_PTR (&e->next, tcache->entries[tc_idx]); + tcache->entries[tc_idx] = e; +@@ -2967,7 +2996,7 @@ tcache_get (size_t tc_idx) + malloc_printerr ("malloc(): unaligned tcache chunk detected"); + tcache->entries[tc_idx] = REVEAL_PTR (e->next); + --(tcache->counts[tc_idx]); +- e->key = NULL; ++ e->key = 0; + return (void *) e; + } + +@@ -4231,7 +4260,7 @@ _int_free (mstate av, mchunkptr p, int h + trust it (it also matches random payload data at a 1 in + 2^ chance), so verify it's not an unlikely + coincidence before aborting. */ +- if (__glibc_unlikely (e->key == tcache)) ++ if (__glibc_unlikely (e->key == tcache_key)) + { + tcache_entry *tmp; + size_t cnt = 0; diff --git a/glibc-rh1888660.patch b/glibc-rh1888660.patch new file mode 100644 index 0000000..ec80b81 --- /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 0000000..6f67ed6 --- /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 0000000..8734628 --- /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 0000000..94b4519 --- /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 0000000..41ce66c --- /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 0000000..9c9c98f --- /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 0000000..4651008 --- /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 0000000..b8d0093 --- /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 0000000..ebd0c33 --- /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 0000000..8c1f7f3 --- /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 0000000..b183d70 --- /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 0000000..7cb18a6 --- /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 0000000..5b90b20 --- /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 0000000..467ece4 --- /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 0000000..3fddefe --- /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 0000000..e991e91 --- /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 0000000..3ac7aa2 --- /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 0000000..e057eeb --- /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 0000000..c92c2cf --- /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 0000000..b2522ad --- /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 0000000..e57fef7 --- /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 0000000..6a68332 --- /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 0000000..e1a085d --- /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 0000000..00b7a71 --- /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 0000000..a0cde6c --- /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 0000000..8588aaa --- /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 0000000..d67e40f --- /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 0000000..1d1295c --- /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 0000000..7da5392 --- /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 0000000..eec1516 --- /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 0000000..4a22e82 --- /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 0000000..b866295 --- /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 0000000..2c55405 --- /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 0000000..02bc403 --- /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 0000000..bce1f3d --- /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 0000000..ea5003f --- /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 0000000..17c35d5 --- /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 0000000..b2e83f8 --- /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 0000000..c6fc26a --- /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 0000000..14cbb8d --- /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 0000000..b05628f --- /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 0000000..08f1448 --- /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 0000000..9fb9d98 --- /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 0000000..3581baa --- /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 0000000..aa0aaaf --- /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 0000000..d52225f --- /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 0000000..48de026 --- /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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int restart; ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++ ++static int ++handle_restart (void) ++{ ++ xdlopen ("tst-audit23mod.so", RTLD_NOW); ++ xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); ++ ++ 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 && memcmp (pre, str, lenpre) == 0; ++} ++ ++static inline bool ++is_vdso (const char *str) ++{ ++ return startswith (str, "linux-gate") ++ || startswith (str, "linux-vdso"); ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ /* We must have either: ++ - One or four 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]; ++ TEST_VERIFY_EXIT (((argc - 1) + 3) < array_length (spargv)); ++ 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-auditmod23.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 expected la_objopen/la_objclose: ++ 1. executable ++ 2. loader ++ 3. libc.so ++ 4. tst-audit23mod.so ++ 5. libc.so (LM_ID_NEWLM). ++ 6. vdso (optional and ignored). */ ++ enum { max_objs = 6 }; ++ struct la_obj_t ++ { ++ char *lname; ++ uintptr_t laddr; ++ Lmid_t lmid; ++ bool closed; ++ } objs[max_objs] = { [0 ... max_objs-1] = { .closed = false } }; ++ size_t nobjs = 0; ++ ++ /* The expected namespaces are one for the audit module, one for the ++ application, and another for the dlmopen on handle_restart. */ ++ enum { max_ns = 3 }; ++ uintptr_t acts[max_ns] = { 0 }; ++ size_t nacts = 0; ++ int last_act = -1; ++ uintptr_t last_act_cookie = -1; ++ bool seen_first_objclose = 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_activity: ")) ++ { ++ uintptr_t cookie; ++ int this_act; ++ int r = sscanf (buffer, "la_activity: %d %"SCNxPTR"", &this_act, ++ &cookie); ++ TEST_COMPARE (r, 2); ++ ++ /* The cookie identifies the object at the head of the link map, ++ so we only add a new namespace if it changes from the previous ++ one. This works since dlmopen is the last in the test body. */ ++ if (cookie != last_act_cookie && last_act_cookie != -1) ++ TEST_COMPARE (last_act, LA_ACT_CONSISTENT); ++ ++ if (this_act == LA_ACT_ADD && acts[nacts] != cookie) ++ { ++ acts[nacts++] = cookie; ++ last_act_cookie = cookie; ++ } ++ /* The LA_ACT_DELETE is called in the reverse order of LA_ACT_ADD ++ at program termination (if the tests adds a dlclose or a library ++ with extra dependencies this will need to be adapted). */ ++ else if (this_act == LA_ACT_DELETE) ++ { ++ last_act_cookie = acts[--nacts]; ++ TEST_COMPARE (acts[nacts], cookie); ++ acts[nacts] = 0; ++ } ++ else if (this_act == LA_ACT_CONSISTENT) ++ { ++ TEST_COMPARE (cookie, last_act_cookie); ++ ++ /* LA_ACT_DELETE must always be followed by an la_objclose. */ ++ if (last_act == LA_ACT_DELETE) ++ TEST_COMPARE (seen_first_objclose, true); ++ else ++ TEST_COMPARE (last_act, LA_ACT_ADD); ++ } ++ ++ last_act = this_act; ++ seen_first_objclose = false; ++ } ++ else if (startswith (buffer, "la_objopen: ")) ++ { ++ char *lname; ++ uintptr_t laddr; ++ Lmid_t lmid; ++ uintptr_t cookie; ++ int r = sscanf (buffer, "la_objopen: %"SCNxPTR" %ms %"SCNxPTR" %ld", ++ &cookie, &lname, &laddr, &lmid); ++ TEST_COMPARE (r, 4); ++ ++ /* la_objclose is not triggered by vDSO because glibc does not ++ unload it. */ ++ if (is_vdso (lname)) ++ continue; ++ if (nobjs == max_objs) ++ FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld", ++ lname, laddr, lmid); ++ objs[nobjs].lname = lname; ++ objs[nobjs].laddr = laddr; ++ objs[nobjs].lmid = lmid; ++ objs[nobjs].closed = false; ++ nobjs++; ++ ++ /* This indirectly checks that la_objopen always comes before ++ la_objclose btween la_activity calls. */ ++ seen_first_objclose = false; ++ } ++ else if (startswith (buffer, "la_objclose: ")) ++ { ++ char *lname; ++ uintptr_t laddr; ++ Lmid_t lmid; ++ uintptr_t cookie; ++ int r = sscanf (buffer, "la_objclose: %"SCNxPTR" %ms %"SCNxPTR" %ld", ++ &cookie, &lname, &laddr, &lmid); ++ TEST_COMPARE (r, 4); ++ ++ for (size_t i = 0; i < nobjs; i++) ++ { ++ if (strcmp (lname, objs[i].lname) == 0 && lmid == objs[i].lmid) ++ { ++ TEST_COMPARE (objs[i].closed, false); ++ objs[i].closed = true; ++ break; ++ } ++ } ++ ++ /* la_objclose should be called after la_activity(LA_ACT_DELETE) for ++ the closed object's namespace. */ ++ TEST_COMPARE (last_act, LA_ACT_DELETE); ++ if (!seen_first_objclose) ++ { ++ TEST_COMPARE (last_act_cookie, cookie); ++ seen_first_objclose = true; ++ } ++ } ++ } ++ ++ for (size_t i = 0; i < nobjs; i++) ++ { ++ TEST_COMPARE (objs[i].closed, true); ++ free (objs[i].lname); ++ } ++ ++ /* la_activity(LA_ACT_CONSISTENT) should be the last callback received. ++ Since only one link map may be not-CONSISTENT at a time, this also ++ ensures la_activity(LA_ACT_CONSISTENT) is the last callback received ++ for every namespace. */ ++ TEST_COMPARE (last_act, LA_ACT_CONSISTENT); ++ ++ free (buffer); ++ xfclose (out); ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/tst-audit23mod.c b/elf/tst-audit23mod.c +new file mode 100644 +index 0000000000000000..30315687037d25e8 +--- /dev/null ++++ b/elf/tst-audit23mod.c +@@ -0,0 +1,23 @@ ++/* Extra module for tst-audit23 ++ 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 ++ . */ ++ ++int ++foo (void) ++{ ++ return 0; ++} +diff --git a/elf/tst-auditmod23.c b/elf/tst-auditmod23.c +new file mode 100644 +index 0000000000000000..d7c60d7a5cbc4f8a +--- /dev/null ++++ b/elf/tst-auditmod23.c +@@ -0,0 +1,74 @@ ++/* Audit module loaded by tst-audit23. ++ 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 ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++struct map_desc_t ++{ ++ char *lname; ++ uintptr_t laddr; ++ Lmid_t lmid; ++}; ++ ++void ++la_activity (uintptr_t *cookie, unsigned int flag) ++{ ++ fprintf (stderr, "%s: %d %"PRIxPTR"\n", __func__, flag, (uintptr_t) cookie); ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *l_name = map->l_name[0] == '\0' ? "mainapp" : map->l_name; ++ fprintf (stderr, "%s: %"PRIxPTR" %s %"PRIxPTR" %ld\n", __func__, ++ (uintptr_t) cookie, l_name, map->l_addr, lmid); ++ ++ struct map_desc_t *map_desc = malloc (sizeof (struct map_desc_t)); ++ if (map_desc == NULL) ++ abort (); ++ ++ map_desc->lname = strdup (l_name); ++ map_desc->laddr = map->l_addr; ++ map_desc->lmid = lmid; ++ ++ *cookie = (uintptr_t) map_desc; ++ ++ return 0; ++} ++ ++unsigned int ++la_objclose (uintptr_t *cookie) ++{ ++ struct map_desc_t *map_desc = (struct map_desc_t *) *cookie; ++ fprintf (stderr, "%s: %"PRIxPTR" %s %"PRIxPTR" %ld\n", __func__, ++ (uintptr_t) cookie, map_desc->lname, map_desc->laddr, ++ map_desc->lmid); ++ ++ return 0; ++} diff --git a/glibc-rh2047981-32.patch b/glibc-rh2047981-32.patch new file mode 100644 index 0000000..2706fe8 --- /dev/null +++ b/glibc-rh2047981-32.patch @@ -0,0 +1,298 @@ +commit 254d3d5aef2fd8430c469e1938209ac100ebf132 +Author: Adhemerval Zanella +Date: Mon Jan 24 10:46:16 2022 -0300 + + elf: Fix initial-exec TLS access on audit modules (BZ #28096) + + For audit modules and dependencies with initial-exec TLS, we can not + set the initial TLS image on default loader initialization because it + would already be set by the audit setup. However, subsequent thread + creation would need to follow the default behaviour. + + This patch fixes it by setting l_auditing link_map field not only + for the audit modules, but also for all its dependencies. This is + used on _dl_allocate_tls_init to avoid the static TLS initialization + at load time. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + +diff --git a/elf/Makefile b/elf/Makefile +index e4955c9f575f9015..3f5f72257a5fbea4 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -344,6 +344,7 @@ tests += \ + tst-audit19b \ + tst-audit2 \ + tst-audit20 \ ++ tst-audit21 \ + tst-audit22 \ + tst-audit23 \ + tst-audit8 \ +@@ -631,6 +632,8 @@ modules-names = \ + tst-auditmod19a \ + tst-auditmod19b \ + tst-auditmod20 \ ++ tst-auditmod21a \ ++ tst-auditmod21b \ + tst-auditmod22 \ + tst-auditmod23 \ + tst-big-note-lib \ +@@ -2041,6 +2044,11 @@ $(objpfx)tst-audit20.out: $(objpfx)tst-auditmod20.so + tst-audit20-ENV = LD_AUDIT=$(objpfx)tst-auditmod20.so + $(objpfx)tst-auditmod20.so: $(libdl) + ++$(objpfx)tst-audit21: $(shared-thread-library) ++$(objpfx)tst-audit21.out: $(objpfx)tst-auditmod21a.so ++$(objpfx)tst-auditmod21a.so: $(objpfx)tst-auditmod21b.so ++tst-audit21-ENV = LD_AUDIT=$(objpfx)tst-auditmod21a.so ++ + $(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so + tst-audit22-ARGS = -- $(host-test-program-cmd) + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 7865fc390c3f3f0a..a918e9a6f585eb72 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -514,8 +514,12 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid) + } + + ++/* Allocate initial TLS. RESULT should be a non-NULL pointer to storage ++ for the TLS space. The DTV may be resized, and so this function may ++ call malloc to allocate that space. The loader's GL(dl_load_tls_lock) ++ is taken when manipulating global TLS-related data in the loader. */ + void * +-_dl_allocate_tls_init (void *result) ++_dl_allocate_tls_init (void *result, bool init_tls) + { + if (result == NULL) + /* The memory allocation failed. */ +@@ -588,7 +592,14 @@ _dl_allocate_tls_init (void *result) + some platforms use in static programs requires it. */ + dtv[map->l_tls_modid].pointer.val = dest; + +- /* Copy the initialization image and clear the BSS part. */ ++ /* Copy the initialization image and clear the BSS part. For ++ audit modules or dependencies with initial-exec TLS, we can not ++ set the initial TLS image on default loader initialization ++ because it would already be set by the audit setup. However, ++ subsequent thread creation would need to follow the default ++ behaviour. */ ++ if (map->l_ns != LM_ID_BASE && !init_tls) ++ continue; + memset (__mempcpy (dest, map->l_tls_initimage, + map->l_tls_initimage_size), '\0', + map->l_tls_blocksize - map->l_tls_initimage_size); +@@ -615,7 +626,7 @@ _dl_allocate_tls (void *mem) + { + return _dl_allocate_tls_init (mem == NULL + ? _dl_allocate_tls_storage () +- : allocate_dtv (mem)); ++ : allocate_dtv (mem), true); + } + rtld_hidden_def (_dl_allocate_tls) + +diff --git a/elf/rtld.c b/elf/rtld.c +index efcbeac6c24c4b7b..caa980dbda3d1a72 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2421,7 +2421,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + into the main thread's TLS area, which we allocated above. + Note: thread-local variables must only be accessed after completing + the next step. */ +- _dl_allocate_tls_init (tcbp); ++ _dl_allocate_tls_init (tcbp, false); + + /* And finally install it for the main thread. */ + if (! tls_init_tp_called) +diff --git a/elf/tst-audit21.c b/elf/tst-audit21.c +new file mode 100644 +index 0000000000000000..3a47ab64d44421ee +--- /dev/null ++++ b/elf/tst-audit21.c +@@ -0,0 +1,42 @@ ++/* Check LD_AUDIT with static TLS. ++ 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 ++ ++static volatile __thread int out __attribute__ ((tls_model ("initial-exec"))); ++ ++static void * ++tf (void *arg) ++{ ++ TEST_COMPARE (out, 0); ++ out = isspace (' '); ++ return NULL; ++} ++ ++int main (int argc, char *argv[]) ++{ ++ TEST_COMPARE (out, 0); ++ out = isspace (' '); ++ ++ pthread_t t = xpthread_create (NULL, tf, NULL); ++ xpthread_join (t); ++ ++ return 0; ++} +diff --git a/elf/tst-auditmod21a.c b/elf/tst-auditmod21a.c +new file mode 100644 +index 0000000000000000..f6d51b5c0531c49d +--- /dev/null ++++ b/elf/tst-auditmod21a.c +@@ -0,0 +1,80 @@ ++/* Check LD_AUDIT with static TLS. ++ 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 ++ ++#define tls_ie __attribute__ ((tls_model ("initial-exec"))) ++ ++__thread int tls_var0 tls_ie; ++__thread int tls_var1 tls_ie = 0x10; ++ ++/* Defined at tst-auditmod21b.so */ ++extern __thread int tls_var2; ++extern __thread int tls_var3; ++ ++static volatile int out; ++ ++static void ++call_libc (void) ++{ ++ /* isspace accesses the initial-exec glibc TLS variables, which are ++ setup in glibc initialization. */ ++ out = isspace (' '); ++} ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ tls_var0 = 0x1; ++ if (tls_var1 != 0x10) ++ abort (); ++ tls_var1 = 0x20; ++ ++ tls_var2 = 0x2; ++ if (tls_var3 != 0x20) ++ abort (); ++ tls_var3 = 0x40; ++ ++ call_libc (); ++ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map* map, Lmid_t lmid, uintptr_t* cookie) ++{ ++ call_libc (); ++ *cookie = (uintptr_t) map; ++ return 0; ++} ++ ++void ++la_activity (uintptr_t* cookie, unsigned int flag) ++{ ++ if (tls_var0 != 0x1 || tls_var1 != 0x20) ++ abort (); ++ call_libc (); ++} ++ ++void ++la_preinit (uintptr_t* cookie) ++{ ++ call_libc (); ++} +diff --git a/elf/tst-auditmod21b.c b/elf/tst-auditmod21b.c +new file mode 100644 +index 0000000000000000..6ba5335b7514c674 +--- /dev/null ++++ b/elf/tst-auditmod21b.c +@@ -0,0 +1,22 @@ ++/* Check LD_AUDIT with static TLS. ++ 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 ++ . */ ++ ++#define tls_ie __attribute__ ((tls_model ("initial-exec"))) ++ ++__thread int tls_var2 tls_ie; ++__thread int tls_var3 tls_ie = 0x20; +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index 5fa45b19987717e1..58170d9da2bf0fa6 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -244,7 +244,7 @@ get_cached_stack (size_t *sizep, void **memp) + memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t)); + + /* Re-initialize the TLS. */ +- _dl_allocate_tls_init (TLS_TPADJ (result)); ++ _dl_allocate_tls_init (TLS_TPADJ (result), true); + + return result; + } +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 29b77b35175c1116..73f4863fd43922b9 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1182,7 +1182,7 @@ extern void _dl_allocate_static_tls (struct link_map *map) attribute_hidden; + /* These are internal entry points to the two halves of _dl_allocate_tls, + only used within rtld.c itself at startup time. */ + extern void *_dl_allocate_tls_storage (void) attribute_hidden; +-extern void *_dl_allocate_tls_init (void *); ++extern void *_dl_allocate_tls_init (void *, bool); + rtld_hidden_proto (_dl_allocate_tls_init) + + /* Deallocate memory allocated with _dl_allocate_tls. */ diff --git a/glibc-rh2047981-33.patch b/glibc-rh2047981-33.patch new file mode 100644 index 0000000..6ce117c --- /dev/null +++ b/glibc-rh2047981-33.patch @@ -0,0 +1,1777 @@ +commit 32612615c58b394c3eb09f020f31310797ad3854 +Author: Adhemerval Zanella +Date: Mon Jan 24 10:46:17 2022 -0300 + + elf: Issue la_symbind for bind-now (BZ #23734) + + The audit symbind callback is not called for binaries built with + -Wl,-z,now or when LD_BIND_NOW=1 is used, nor the PLT tracking callbacks + (plt_enter and plt_exit) since this would change the expected + program semantics (where no PLT is expected) and would have performance + implications (such as for BZ#15533). + + LAV_CURRENT is also bumped to indicate the audit ABI change (where + la_symbind flags are set by the loader to indicate no possible PLT + trace). + + To handle powerpc64 ELFv1 function descriptor, _dl_audit_symbind + requires to know whether bind-now is used so the symbol value is + updated to function text segment instead of the OPD (for lazy binding + this is done by PPC64_LOAD_FUNCPTR on _dl_runtime_resolve). + + Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, + powerpc64-linux-gnu. + + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + +Conflicts: + elf/Makefile + +diff --git a/bits/link_lavcurrent.h b/bits/link_lavcurrent.h +index 44fbea1e8060997f..c48835d12b512355 100644 +--- a/bits/link_lavcurrent.h ++++ b/bits/link_lavcurrent.h +@@ -22,4 +22,4 @@ + #endif + + /* Version numbers for la_version handshake interface. */ +-#define LAV_CURRENT 1 ++#define LAV_CURRENT 2 +diff --git a/elf/Makefile b/elf/Makefile +index 3f5f72257a5fbea4..78147ed2dbcaf4c0 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -347,6 +347,12 @@ tests += \ + tst-audit21 \ + tst-audit22 \ + tst-audit23 \ ++ tst-audit24a \ ++ tst-audit24b \ ++ tst-audit24c \ ++ tst-audit24d \ ++ tst-audit25a \ ++ tst-audit25b \ + tst-audit8 \ + tst-audit9 \ + tst-auditmany \ +@@ -611,6 +617,18 @@ modules-names = \ + tst-audit18mod \ + tst-audit19bmod \ + tst-audit23mod \ ++ tst-audit24amod1 \ ++ tst-audit24amod2 \ ++ tst-audit24bmod1 \ ++ tst-audit24bmod2 \ ++ tst-audit24dmod1 \ ++ tst-audit24dmod2 \ ++ tst-audit24dmod3 \ ++ tst-audit24dmod4 \ ++ tst-audit25mod1 \ ++ tst-audit25mod2 \ ++ tst-audit25mod3 \ ++ tst-audit25mod4 \ + tst-auditlogmod-1 \ + tst-auditlogmod-2 \ + tst-auditlogmod-3 \ +@@ -636,6 +654,11 @@ modules-names = \ + tst-auditmod21b \ + tst-auditmod22 \ + tst-auditmod23 \ ++ tst-auditmod24a \ ++ tst-auditmod24b \ ++ tst-auditmod24c \ ++ tst-auditmod24d \ ++ tst-auditmod25 \ + tst-big-note-lib \ + tst-deep1mod1 \ + tst-deep1mod2 \ +@@ -831,7 +854,8 @@ modules-execstack-yes = tst-execstack-mod + extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) + + # filtmod1.so has a special rule +-modules-names-nobuild := filtmod1 ++modules-names-nobuild := filtmod1 \ ++ tst-audit24bmod1 tst-audit24bmod2.so + + tests += $(tests-static) + +@@ -2057,6 +2081,69 @@ $(objpfx)tst-audit23.out: $(objpfx)tst-auditmod23.so \ + $(objpfx)tst-audit23mod.so + tst-audit23-ARGS = -- $(host-test-program-cmd) + ++$(objpfx)tst-audit24a.out: $(objpfx)tst-auditmod24a.so ++$(objpfx)tst-audit24a: $(objpfx)tst-audit24amod1.so \ ++ $(objpfx)tst-audit24amod2.so ++tst-audit24a-ENV = LD_AUDIT=$(objpfx)tst-auditmod24a.so ++LDFLAGS-tst-audit24a = -Wl,-z,now ++ ++$(objpfx)tst-audit24b.out: $(objpfx)tst-auditmod24b.so ++$(objpfx)tst-audit24b: $(objpfx)tst-audit24bmod1.so \ ++ $(objpfx)tst-audit24bmod2.so ++$(objpfx)tst-audit24bmod1: $(objpfx)tst-audit24bmod2.so ++# The test checks if a library without .gnu.version correctly calls the ++# audit callbacks. So it uses an explicit link rule to avoid linking ++# against libc.so. ++$(objpfx)tst-audit24bmod1.so: $(objpfx)tst-audit24bmod1.os ++ $(CC) -nostdlib -nostartfiles -shared -o $@.new $(objpfx)tst-audit24bmod1.os \ ++ -Wl,-z,now ++ $(call after-link,$@.new) ++ mv -f $@.new $@ ++CFLAGS-.os += $(call elide-stack-protector,.os,tst-audit24bmod1) ++$(objpfx)tst-audit24bmod2.so: $(objpfx)tst-audit24bmod2.os ++ $(CC) -nostdlib -nostartfiles -shared -o $@.new $(objpfx)tst-audit24bmod2.os ++ $(call after-link,$@.new) ++ mv -f $@.new $@ ++CFLAGS-.os += $(call elide-stack-protector,.os,tst-audit24bmod2) ++tst-audit24b-ENV = LD_AUDIT=$(objpfx)tst-auditmod24b.so ++LDFLAGS-tst-audit24b = -Wl,-z,now ++ ++# Same as tst-audit24a, but tests LD_BIND_NOW ++$(objpfx)tst-audit24c.out: $(objpfx)tst-auditmod24c.so ++$(objpfx)tst-audit24c: $(objpfx)tst-audit24amod1.so \ ++ $(objpfx)tst-audit24amod2.so ++tst-audit24c-ENV = LD_BIND_NOW=1 LD_AUDIT=$(objpfx)tst-auditmod24c.so ++LDFLAGS-tst-audit24b = -Wl,-z,lazy ++ ++$(objpfx)tst-audit24d.out: $(objpfx)tst-auditmod24d.so ++$(objpfx)tst-audit24d: $(objpfx)tst-audit24dmod1.so \ ++ $(objpfx)tst-audit24dmod2.so ++$(objpfx)tst-audit24dmod1.so: $(objpfx)tst-audit24dmod3.so ++LDFLAGS-tst-audit24dmod1.so = -Wl,-z,now ++$(objpfx)tst-audit24dmod2.so: $(objpfx)tst-audit24dmod4.so ++LDFLAGS-tst-audit24dmod2.so = -Wl,-z,lazy ++tst-audit24d-ENV = LD_AUDIT=$(objpfx)tst-auditmod24d.so ++LDFLAGS-tst-audit24d = -Wl,-z,lazy ++ ++$(objpfx)tst-audit25a.out: $(objpfx)tst-auditmod25.so ++$(objpfx)tst-audit25a: $(objpfx)tst-audit25mod1.so \ ++ $(objpfx)tst-audit25mod2.so \ ++ $(objpfx)tst-audit25mod3.so \ ++ $(objpfx)tst-audit25mod4.so ++$(objpfx)tst-audit25mod1.so: $(objpfx)tst-audit25mod3.so ++LDFLAGS-tst-audit25mod1.so = -Wl,-z,now ++$(objpfx)tst-audit25mod2.so: $(objpfx)tst-audit25mod4.so ++LDFLAGS-tst-audit25mod2.so = -Wl,-z,lazy ++tst-audit25a-ARGS = -- $(host-test-program-cmd) ++ ++$(objpfx)tst-audit25b.out: $(objpfx)tst-auditmod25.so ++$(objpfx)tst-audit25b: $(objpfx)tst-audit25mod1.so \ ++ $(objpfx)tst-audit25mod2.so \ ++ $(objpfx)tst-audit25mod3.so \ ++ $(objpfx)tst-audit25mod4.so ++LDFLAGS-tst-audit25b = -Wl,-z,now ++tst-audit25b-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-audit.c b/elf/dl-audit.c +index 152712b12fed6de2..72a50717ef60a357 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -178,16 +178,23 @@ _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])); ++ bool for_jmp_slot = reloc_result == NULL; ++ ++ /* Compute index of the symbol entry in the symbol table of the DSO ++ with the definition. */ ++ unsigned int boundndx = defsym - (ElfW(Sym) *) D_PTR (result, ++ l_info[DT_SYMTAB]); ++ if (!for_jmp_slot) ++ { ++ reloc_result->bound = result; ++ reloc_result->boundndx = boundndx; ++ } + + 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; ++ if (!for_jmp_slot) ++ reloc_result->enterexit = (1u << DL_NNS) - 1; + return; + } + +@@ -199,12 +206,13 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + 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; ++ uint32_t 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); ++ uintptr_t new_value = (uintptr_t) sym.st_value; + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + /* XXX Check whether both DSOs must request action or only one */ +@@ -215,37 +223,41 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + { + 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); ++ flags |= for_jmp_slot ? LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT ++ : 0; ++ new_value = afct->symbind (&sym, 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; ++ sym.st_value = for_jmp_slot ++ ? DL_FIXUP_BINDNOW_ADDR_VALUE (new_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)); ++ enterexit &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT); ++ 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)); ++ 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); ++ if (!for_jmp_slot) ++ { ++ reloc_result->enterexit = enterexit; ++ reloc_result->flags = flags; ++ } ++ ++ DL_FIXUP_BINDNOW_RELOC (value, new_value, sym.st_value); + } + + void +diff --git a/elf/do-rel.h b/elf/do-rel.h +index 0b04d1a0bf28b9f4..43c80e1c0067d9ca 100644 +--- a/elf/do-rel.h ++++ b/elf/do-rel.h +@@ -16,6 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++ + /* This file may be included twice, to define both + `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. */ + +@@ -123,6 +125,10 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[], + + for (; r < end; ++r) + { ++ ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff; ++ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)]; ++ void *const r_addr_arg = (void *) (l_addr + r->r_offset); ++ const struct r_found_version *rversion = &map->l_versions[ndx]; + #if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP + if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE) + { +@@ -133,10 +139,19 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[], + } + #endif + +- ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff; +- 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); ++ elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, ++ skip_ifunc); ++#if defined SHARED && !defined RTLD_BOOTSTRAP ++ if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT ++ && GLRO(dl_naudit) > 0) ++ { ++ struct link_map *sym_map ++ = RESOLVE_MAP (map, scope, &sym, rversion, ++ ELF_MACHINE_JMP_SLOT); ++ if (sym != NULL) ++ _dl_audit_symbind (map, NULL, sym, r_addr_arg, sym_map); ++ } ++#endif + } + + #if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP +@@ -158,17 +173,33 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[], + else + { + for (; r < end; ++r) ++ { ++ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)]; ++ void *const r_addr_arg = (void *) (l_addr + r->r_offset); + # ifdef ELF_MACHINE_IRELATIVE +- if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE) +- { +- if (r2 == NULL) +- r2 = r; +- end2 = r; +- } +- else ++ if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE) ++ { ++ if (r2 == NULL) ++ r2 = r; ++ end2 = r; ++ continue; ++ } + # endif +- elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL, +- (void *) (l_addr + r->r_offset), skip_ifunc); ++ elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg, ++ skip_ifunc); ++# if defined SHARED && !defined RTLD_BOOTSTRAP ++ if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT ++ && GLRO(dl_naudit) > 0) ++ { ++ struct link_map *sym_map ++ = RESOLVE_MAP (map, scope, &sym, ++ (struct r_found_version *) NULL, ++ ELF_MACHINE_JMP_SLOT); ++ if (sym != NULL) ++ _dl_audit_symbind (map, NULL , sym,r_addr_arg, sym_map); ++ } ++# endif ++ } + + # ifdef ELF_MACHINE_IRELATIVE + if (r2 != NULL) +diff --git a/elf/sotruss-lib.c b/elf/sotruss-lib.c +index f0a7e55599d76714..e1ac53f327a7571b 100644 +--- a/elf/sotruss-lib.c ++++ b/elf/sotruss-lib.c +@@ -17,6 +17,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + #include + #include +@@ -232,6 +233,12 @@ uintptr_t + la_symbind (Elf_Sym *sym, unsigned int ndx, uintptr_t *refcook, + uintptr_t *defcook, unsigned int *flags, const char *symname) + { ++ if (*flags & LA_SYMB_NOPLTENTER) ++ warnx ("cannot trace PLT enter (bind-now enabled)"); ++ ++ if (do_exit && *flags & LA_SYMB_NOPLTEXIT) ++ warnx ("cannot trace PLT exit (bind-now enabled)"); ++ + if (!do_exit) + *flags = LA_SYMB_NOPLTEXIT; + +diff --git a/elf/tst-audit24a.c b/elf/tst-audit24a.c +new file mode 100644 +index 0000000000000000..a1781c9b45f18fa0 +--- /dev/null ++++ b/elf/tst-audit24a.c +@@ -0,0 +1,36 @@ ++/* LD_AUDIT test for la_symbind and bind-now. ++ 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 ++ ++int tst_audit24amod1_func1 (void); ++int tst_audit24amod1_func2 (void); ++int tst_audit24amod2_func1 (void); ++ ++int ++do_test (void) ++{ ++ TEST_COMPARE (tst_audit24amod1_func1 (), 1); ++ TEST_COMPARE (tst_audit24amod1_func2 (), 2); ++ TEST_COMPARE (tst_audit24amod2_func1 (), 10); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit24amod1.c b/elf/tst-audit24amod1.c +new file mode 100644 +index 0000000000000000..0289a4abefbc7bbb +--- /dev/null ++++ b/elf/tst-audit24amod1.c +@@ -0,0 +1,31 @@ ++/* Module used by tst-audit24a. ++ 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 ++ ++_Noreturn int ++tst_audit24amod1_func1 (void) ++{ ++ abort (); ++} ++ ++int ++tst_audit24amod1_func2 (void) ++{ ++ return 2; ++} +diff --git a/elf/tst-audit24amod2.c b/elf/tst-audit24amod2.c +new file mode 100644 +index 0000000000000000..1562afc9dfc1b9b3 +--- /dev/null ++++ b/elf/tst-audit24amod2.c +@@ -0,0 +1,25 @@ ++/* Module used by tst-audit24a. ++ 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 ++ ++_Noreturn int ++tst_audit24amod2_func1 (void) ++{ ++ abort (); ++} +diff --git a/elf/tst-audit24b.c b/elf/tst-audit24b.c +new file mode 100644 +index 0000000000000000..567bee52c27f4361 +--- /dev/null ++++ b/elf/tst-audit24b.c +@@ -0,0 +1,37 @@ ++/* LD_AUDIT test for la_symbind and bind-now. ++ 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 ++ . */ ++ ++/* This is similar to tst-audit24a, with the difference this modules ++ does not have the .gnu.version section header. */ ++ ++#include ++#include ++ ++int tst_audit24bmod1_func1 (void); ++int tst_audit24bmod1_func2 (void); ++ ++int ++do_test (void) ++{ ++ TEST_COMPARE (tst_audit24bmod1_func1 (), 1); ++ TEST_COMPARE (tst_audit24bmod1_func2 (), 2); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit24bmod1.c b/elf/tst-audit24bmod1.c +new file mode 100644 +index 0000000000000000..57ce14a01bf72fb6 +--- /dev/null ++++ b/elf/tst-audit24bmod1.c +@@ -0,0 +1,31 @@ ++/* Module used by tst-audit24c. ++ 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 ++ . */ ++ ++int tst_audit24bmod2_func1 (void); ++ ++int ++tst_audit24bmod1_func1 (void) ++{ ++ return -1; ++} ++ ++int ++tst_audit24bmod1_func2 (void) ++{ ++ return tst_audit24bmod2_func1 (); ++} +diff --git a/elf/tst-audit24bmod2.c b/elf/tst-audit24bmod2.c +new file mode 100644 +index 0000000000000000..b298ce0a05bf2db2 +--- /dev/null ++++ b/elf/tst-audit24bmod2.c +@@ -0,0 +1,23 @@ ++/* Module used by tst-audit24b. ++ 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 ++ . */ ++ ++int ++tst_audit24bmod2_func1 (void) ++{ ++ return -1; ++} +diff --git a/elf/tst-audit24c.c b/elf/tst-audit24c.c +new file mode 100644 +index 0000000000000000..46ed328756067276 +--- /dev/null ++++ b/elf/tst-audit24c.c +@@ -0,0 +1,2 @@ ++/* It tests LD_BIND_NOW=1 instead of linking with -Wl,-z,now */ ++#include "tst-audit24a.c" +diff --git a/elf/tst-audit24d.c b/elf/tst-audit24d.c +new file mode 100644 +index 0000000000000000..543f3b86a6bbdead +--- /dev/null ++++ b/elf/tst-audit24d.c +@@ -0,0 +1,36 @@ ++/* LD_AUDIT test for la_symbind and bind-now. ++ 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 ++ ++int tst_audit24dmod1_func1 (void); ++int tst_audit24dmod1_func2 (void); ++int tst_audit24dmod2_func1 (void); ++ ++int ++do_test (void) ++{ ++ TEST_COMPARE (tst_audit24dmod1_func1 (), 1); ++ TEST_COMPARE (tst_audit24dmod1_func2 (), 32); ++ TEST_COMPARE (tst_audit24dmod2_func1 (), 10); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit24dmod1.c b/elf/tst-audit24dmod1.c +new file mode 100644 +index 0000000000000000..e563f69d638ac3f5 +--- /dev/null ++++ b/elf/tst-audit24dmod1.c +@@ -0,0 +1,33 @@ ++/* Module used by tst-audit24d. ++ 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 ++ ++int tst_audit24dmod3_func1 (void); ++ ++_Noreturn int ++tst_audit24dmod1_func1 (void) ++{ ++ abort (); ++} ++ ++int ++tst_audit24dmod1_func2 (void) ++{ ++ return 2 + tst_audit24dmod3_func1 ();; ++} +diff --git a/elf/tst-audit24dmod2.c b/elf/tst-audit24dmod2.c +new file mode 100644 +index 0000000000000000..03fe9381281e5790 +--- /dev/null ++++ b/elf/tst-audit24dmod2.c +@@ -0,0 +1,28 @@ ++/* Module for tst-audit24d. ++ 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 ++ ++int tst_audit24dmod4_func1 (void); ++ ++_Noreturn int ++tst_audit24dmod2_func1 (void) ++{ ++ tst_audit24dmod4_func1 (); ++ abort (); ++} +diff --git a/elf/tst-audit24dmod3.c b/elf/tst-audit24dmod3.c +new file mode 100644 +index 0000000000000000..106d517d2887d76c +--- /dev/null ++++ b/elf/tst-audit24dmod3.c +@@ -0,0 +1,31 @@ ++/* Module for tst-audit24d. ++ 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 ++ ++_Noreturn int ++tst_audit24dmod3_func1 (void) ++{ ++ abort (); ++} ++ ++int ++tst_audit24dmod3_func2 (void) ++{ ++ return 4; ++} +diff --git a/elf/tst-audit24dmod4.c b/elf/tst-audit24dmod4.c +new file mode 100644 +index 0000000000000000..1da3b46917ba1083 +--- /dev/null ++++ b/elf/tst-audit24dmod4.c +@@ -0,0 +1,25 @@ ++/* Module for tst-audit24d. ++ 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 ++ ++_Noreturn int ++tst_audit24dmod4_func1 (void) ++{ ++ abort (); ++} +diff --git a/elf/tst-audit25a.c b/elf/tst-audit25a.c +new file mode 100644 +index 0000000000000000..49173e862516e876 +--- /dev/null ++++ b/elf/tst-audit25a.c +@@ -0,0 +1,129 @@ ++/* Check LD_AUDIT and LD_BIND_NOW. ++ 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 ++#include ++#include ++#include ++ ++static int restart; ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++ ++void tst_audit25mod1_func1 (void); ++void tst_audit25mod1_func2 (void); ++void tst_audit25mod2_func1 (void); ++void tst_audit25mod2_func2 (void); ++ ++static int ++handle_restart (void) ++{ ++ tst_audit25mod1_func1 (); ++ tst_audit25mod1_func2 (); ++ tst_audit25mod2_func1 (); ++ tst_audit25mod2_func2 (); ++ ++ 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 or four 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 (); ++ ++ setenv ("LD_AUDIT", "tst-auditmod25.so", 0); ++ ++ 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; ++ TEST_VERIFY_EXIT (i < array_length (spargv)); ++ ++ { ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit25a", 0, ++ sc_allow_stderr); ++ ++ /* tst-audit25a is build with -Wl,-z,lazy and tst-audit25mod1 with ++ -Wl,-z,now; so only tst_audit25mod3_func1 should be expected to ++ have LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT. */ ++ TEST_COMPARE_STRING (result.err.buffer, ++ "la_symbind: tst_audit25mod3_func1 1\n" ++ "la_symbind: tst_audit25mod1_func1 0\n" ++ "la_symbind: tst_audit25mod1_func2 0\n" ++ "la_symbind: tst_audit25mod2_func1 0\n" ++ "la_symbind: tst_audit25mod4_func1 0\n" ++ "la_symbind: tst_audit25mod2_func2 0\n"); ++ ++ support_capture_subprocess_free (&result); ++ } ++ ++ { ++ setenv ("LD_BIND_NOW", "1", 0); ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit25a", 0, ++ sc_allow_stderr); ++ ++ /* With LD_BIND_NOW all symbols are expected to have ++ LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT. Also the resolution ++ order is done in breadth-first order. */ ++ TEST_COMPARE_STRING (result.err.buffer, ++ "la_symbind: tst_audit25mod4_func1 1\n" ++ "la_symbind: tst_audit25mod3_func1 1\n" ++ "la_symbind: tst_audit25mod1_func1 1\n" ++ "la_symbind: tst_audit25mod2_func1 1\n" ++ "la_symbind: tst_audit25mod1_func2 1\n" ++ "la_symbind: tst_audit25mod2_func2 1\n"); ++ ++ support_capture_subprocess_free (&result); ++ } ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/tst-audit25b.c b/elf/tst-audit25b.c +new file mode 100644 +index 0000000000000000..a56638d501f9bff5 +--- /dev/null ++++ b/elf/tst-audit25b.c +@@ -0,0 +1,128 @@ ++/* Check LD_AUDIT and LD_BIND_NOW. ++ 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 ++#include ++#include ++ ++static int restart; ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++ ++void tst_audit25mod1_func1 (void); ++void tst_audit25mod1_func2 (void); ++void tst_audit25mod2_func1 (void); ++void tst_audit25mod2_func2 (void); ++ ++static int ++handle_restart (void) ++{ ++ tst_audit25mod1_func1 (); ++ tst_audit25mod1_func2 (); ++ tst_audit25mod2_func1 (); ++ tst_audit25mod2_func2 (); ++ ++ 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 && memcmp (pre, str, lenpre) == 0; ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ /* We must have either: ++ - One or four 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 (); ++ ++ setenv ("LD_AUDIT", "tst-auditmod25.so", 0); ++ ++ 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; ++ ++ { ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit25a", 0, ++ sc_allow_stderr); ++ ++ /* tst-audit25a and tst-audit25mod1 are built with -Wl,-z,now, but ++ tst-audit25mod2 is built with -Wl,-z,lazy. So only ++ tst_audit25mod4_func1 (called by tst_audit25mod2_func1) should not ++ have LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT. */ ++ TEST_COMPARE_STRING (result.err.buffer, ++ "la_symbind: tst_audit25mod3_func1 1\n" ++ "la_symbind: tst_audit25mod1_func1 1\n" ++ "la_symbind: tst_audit25mod2_func1 1\n" ++ "la_symbind: tst_audit25mod1_func2 1\n" ++ "la_symbind: tst_audit25mod2_func2 1\n" ++ "la_symbind: tst_audit25mod4_func1 0\n"); ++ ++ support_capture_subprocess_free (&result); ++ } ++ ++ { ++ setenv ("LD_BIND_NOW", "1", 0); ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit25a", 0, ++ sc_allow_stderr); ++ ++ /* With LD_BIND_NOW all symbols are expected to have ++ LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT. Also the resolution ++ order is done in breadth-first order. */ ++ TEST_COMPARE_STRING (result.err.buffer, ++ "la_symbind: tst_audit25mod4_func1 1\n" ++ "la_symbind: tst_audit25mod3_func1 1\n" ++ "la_symbind: tst_audit25mod1_func1 1\n" ++ "la_symbind: tst_audit25mod2_func1 1\n" ++ "la_symbind: tst_audit25mod1_func2 1\n" ++ "la_symbind: tst_audit25mod2_func2 1\n"); ++ ++ support_capture_subprocess_free (&result); ++ } ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/tst-audit25mod1.c b/elf/tst-audit25mod1.c +new file mode 100644 +index 0000000000000000..a132e34a9b2cf51f +--- /dev/null ++++ b/elf/tst-audit25mod1.c +@@ -0,0 +1,30 @@ ++/* Module used by tst-audit25. ++ 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 ++ . */ ++ ++void tst_audit25mod3_func1 (void); ++ ++void ++tst_audit25mod1_func1 (void) ++{ ++ tst_audit25mod3_func1 (); ++} ++ ++void ++tst_audit25mod1_func2 (void) ++{ ++} +diff --git a/elf/tst-audit25mod2.c b/elf/tst-audit25mod2.c +new file mode 100644 +index 0000000000000000..92da26fa80b202c2 +--- /dev/null ++++ b/elf/tst-audit25mod2.c +@@ -0,0 +1,30 @@ ++/* Module used by tst-audit25. ++ 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 ++ . */ ++ ++void tst_audit25mod4_func1 (void); ++ ++void ++tst_audit25mod2_func1 (void) ++{ ++ tst_audit25mod4_func1 (); ++} ++ ++void ++tst_audit25mod2_func2 (void) ++{ ++} +diff --git a/elf/tst-audit25mod3.c b/elf/tst-audit25mod3.c +new file mode 100644 +index 0000000000000000..af83e8919083adef +--- /dev/null ++++ b/elf/tst-audit25mod3.c +@@ -0,0 +1,22 @@ ++/* Module used by tst-audit25. ++ 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 ++ . */ ++ ++void ++tst_audit25mod3_func1 (void) ++{ ++} +diff --git a/elf/tst-audit25mod4.c b/elf/tst-audit25mod4.c +new file mode 100644 +index 0000000000000000..6cdf34357582da16 +--- /dev/null ++++ b/elf/tst-audit25mod4.c +@@ -0,0 +1,22 @@ ++/* Module used by tst-audit25. ++ 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 ++ . */ ++ ++void ++tst_audit25mod4_func1 (void) ++{ ++} +diff --git a/elf/tst-auditmod24.h b/elf/tst-auditmod24.h +new file mode 100644 +index 0000000000000000..5fdbfef12dac2b2a +--- /dev/null ++++ b/elf/tst-auditmod24.h +@@ -0,0 +1,29 @@ ++/* Auxiliary functions for tst-audit24x. ++ 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 ++ . */ ++ ++#ifndef _TST_AUDITMOD24_H ++#define _TST_AUDITMOD24_H ++ ++static void ++test_symbind_flags (unsigned int flags) ++{ ++ if ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) == 0) ++ abort (); ++} ++ ++#endif +diff --git a/elf/tst-auditmod24a.c b/elf/tst-auditmod24a.c +new file mode 100644 +index 0000000000000000..d8e88f3984af1707 +--- /dev/null ++++ b/elf/tst-auditmod24a.c +@@ -0,0 +1,114 @@ ++/* Audit modules for tst-audit24a. ++ 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 ++ ++#define AUDIT24_COOKIE 0x1 ++#define AUDIT24MOD1_COOKIE 0x2 ++#define AUDIT24MOD2_COOKIE 0x3 ++ ++#ifndef TEST_NAME ++# define TEST_NAME "tst-audit24a" ++#endif ++#ifndef TEST_MOD ++# define TEST_MOD TEST_NAME ++#endif ++#ifndef TEST_FUNC ++# define TEST_FUNC "tst_audit24a" ++#endif ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? TEST_NAME : p + 1; ++ ++ uintptr_t ck = -1; ++ if (strcmp (l_name, TEST_MOD "mod1.so") == 0) ++ ck = AUDIT24MOD1_COOKIE; ++ else if (strcmp (l_name, TEST_MOD "mod2.so") == 0) ++ ck = AUDIT24MOD2_COOKIE; ++ else if (strcmp (l_name, TEST_NAME) == 0) ++ ck = AUDIT24_COOKIE; ++ ++ *cookie = ck; ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++static int ++tst_func1 (void) ++{ ++ return 1; ++} ++ ++static int ++tst_func2 (void) ++{ ++ return 10; ++} ++ ++#if __ELF_NATIVE_CLASS == 64 ++uintptr_t ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#else ++uintptr_t ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#endif ++{ ++ if (*refcook == AUDIT24_COOKIE) ++ { ++ if (*defcook == AUDIT24MOD1_COOKIE) ++ { ++ /* Check if bind-now symbols are advertised to not call the PLT ++ hooks. */ ++ test_symbind_flags (*flags); ++ ++ if (strcmp (symname, TEST_FUNC "mod1_func1") == 0) ++ return (uintptr_t) tst_func1; ++ else if (strcmp (symname, TEST_FUNC "mod1_func2") == 0) ++ return sym->st_value; ++ abort (); ++ } ++ if (*defcook == AUDIT24MOD2_COOKIE ++ && (strcmp (symname, TEST_FUNC "mod2_func1") == 0)) ++ { ++ test_symbind_flags (*flags); ++ ++ return (uintptr_t) tst_func2; ++ } ++ ++ /* malloc functions. */ ++ return sym->st_value; ++ } ++ ++ abort (); ++} +diff --git a/elf/tst-auditmod24b.c b/elf/tst-auditmod24b.c +new file mode 100644 +index 0000000000000000..e98f6d5ec528fe03 +--- /dev/null ++++ b/elf/tst-auditmod24b.c +@@ -0,0 +1,104 @@ ++/* Audit modules for tst-audit24b. ++ 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 ++ ++#define TEST_NAME "tst-audit24b" ++#define TEST_FUNC "tst_audit24b" ++ ++#define AUDIT24_COOKIE 0x1 ++#define AUDIT24MOD1_COOKIE 0x2 ++#define AUDIT24MOD2_COOKIE 0x3 ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? TEST_NAME : p + 1; ++ ++ uintptr_t ck = -1; ++ if (strcmp (l_name, TEST_NAME "mod1.so") == 0) ++ ck = AUDIT24MOD1_COOKIE; ++ else if (strcmp (l_name, TEST_NAME "mod2.so") == 0) ++ ck = AUDIT24MOD2_COOKIE; ++ else if (strcmp (l_name, TEST_NAME) == 0) ++ ck = AUDIT24_COOKIE; ++ ++ *cookie = ck; ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++static int ++tst_func1 (void) ++{ ++ return 1; ++} ++ ++static int ++tst_func2 (void) ++{ ++ return 2; ++} ++ ++#if __ELF_NATIVE_CLASS == 64 ++uintptr_t ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#else ++uintptr_t ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#endif ++{ ++ if (*refcook == AUDIT24_COOKIE) ++ { ++ if (*defcook == AUDIT24MOD1_COOKIE) ++ { ++ if (strcmp (symname, TEST_FUNC "mod1_func1") == 0) ++ return (uintptr_t) tst_func1; ++ else if (strcmp (symname, TEST_FUNC "mod1_func2") == 0) ++ return sym->st_value; ++ abort (); ++ } ++ /* malloc functions. */ ++ return sym->st_value; ++ } ++ else if (*refcook == AUDIT24MOD1_COOKIE) ++ { ++ if (*defcook == AUDIT24MOD2_COOKIE ++ && (strcmp (symname, TEST_FUNC "mod2_func1") == 0)) ++ { ++ test_symbind_flags (*flags); ++ return (uintptr_t) tst_func2; ++ } ++ } ++ ++ abort (); ++} +diff --git a/elf/tst-auditmod24c.c b/elf/tst-auditmod24c.c +new file mode 100644 +index 0000000000000000..67e62c9d332f48a7 +--- /dev/null ++++ b/elf/tst-auditmod24c.c +@@ -0,0 +1,3 @@ ++#define TEST_NAME "tst-audit24c" ++#define TEST_MOD "tst-audit24a" ++#include "tst-auditmod24a.c" +diff --git a/elf/tst-auditmod24d.c b/elf/tst-auditmod24d.c +new file mode 100644 +index 0000000000000000..8c803ecc0a48f21b +--- /dev/null ++++ b/elf/tst-auditmod24d.c +@@ -0,0 +1,120 @@ ++/* Audit module for tst-audit24d. ++ 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 ++ ++#define AUDIT24_COOKIE 0x0 ++#define AUDIT24MOD1_COOKIE 0x1 ++#define AUDIT24MOD2_COOKIE 0x2 ++#define AUDIT24MOD3_COOKIE 0x3 ++#define AUDIT24MOD4_COOKIE 0x4 ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? "tst-audit24d" : p + 1; ++ ++ uintptr_t ck = -1; ++ if (strcmp (l_name, "tst-audit24dmod1.so") == 0) ++ ck = AUDIT24MOD1_COOKIE; ++ else if (strcmp (l_name, "tst-audit24dmod2.so") == 0) ++ ck = AUDIT24MOD2_COOKIE; ++ else if (strcmp (l_name, "tst-audit24dmod3.so") == 0) ++ ck = AUDIT24MOD3_COOKIE; ++ else if (strcmp (l_name, "tst-audit24dmod.so") == 0) ++ ck = AUDIT24MOD4_COOKIE; ++ else if (strcmp (l_name, "tst-audit24d") == 0) ++ ck = AUDIT24_COOKIE; ++ ++ *cookie = ck; ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++static int ++tst_audit24dmod1_func1 (void) ++{ ++ return 1; ++} ++ ++static int ++tst_audit24dmod2_func1 (void) ++{ ++ return 10; ++} ++ ++static int ++tst_audit24dmod3_func1 (void) ++{ ++ return 30; ++} ++ ++#include ++ ++#if __ELF_NATIVE_CLASS == 64 ++uintptr_t ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#else ++uintptr_t ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#endif ++{ ++ if (*refcook == AUDIT24_COOKIE) ++ { ++ if (*defcook == AUDIT24MOD1_COOKIE) ++ { ++ if (strcmp (symname, "tst_audit24dmod1_func1") == 0) ++ return (uintptr_t) tst_audit24dmod1_func1; ++ else if (strcmp (symname, "tst_audit24dmod1_func2") == 0) ++ return sym->st_value; ++ abort (); ++ } ++ if (*defcook == AUDIT24MOD2_COOKIE ++ && (strcmp (symname, "tst_audit24dmod2_func1") == 0)) ++ return (uintptr_t) tst_audit24dmod2_func1; ++ ++ /* malloc functions. */ ++ return sym->st_value; ++ } ++ else if (*refcook == AUDIT24MOD1_COOKIE) ++ { ++ if (*defcook == AUDIT24MOD3_COOKIE ++ && strcmp (symname, "tst_audit24dmod3_func1") == 0) ++ { ++ test_symbind_flags (*flags); ++ ++ return (uintptr_t) tst_audit24dmod3_func1; ++ } ++ } ++ ++ abort (); ++} +diff --git a/elf/tst-auditmod25.c b/elf/tst-auditmod25.c +new file mode 100644 +index 0000000000000000..526f5c54bc2c3b8c +--- /dev/null ++++ b/elf/tst-auditmod25.c +@@ -0,0 +1,79 @@ ++/* Audit modules for tst-audit25a. ++ 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 ++ ++#define AUDIT25_COOKIE 0x1 ++#define AUDIT25MOD1_COOKIE 0x2 ++#define AUDIT25MOD2_COOKIE 0x3 ++#define AUDIT25MOD3_COOKIE 0x2 ++#define AUDIT25MOD4_COOKIE 0x3 ++ ++#define TEST_NAME "tst-audit25" ++#define TEST_MOD "tst-audit25" ++#define TEST_FUNC "tst_audit25" ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? TEST_NAME : p + 1; ++ ++ uintptr_t ck = -1; ++ if (strcmp (l_name, TEST_MOD "mod1.so") == 0) ++ ck = AUDIT25MOD1_COOKIE; ++ else if (strcmp (l_name, TEST_MOD "mod2.so") == 0) ++ ck = AUDIT25MOD2_COOKIE; ++ else if (strcmp (l_name, TEST_MOD "mod3.so") == 0) ++ ck = AUDIT25MOD3_COOKIE; ++ else if (strcmp (l_name, TEST_MOD "mod4.so") == 0) ++ ck = AUDIT25MOD4_COOKIE; ++ else if (strncmp (l_name, TEST_NAME, strlen (TEST_NAME)) == 0) ++ ck = AUDIT25_COOKIE; ++ ++ *cookie = ck; ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++#if __ELF_NATIVE_CLASS == 64 ++uintptr_t ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#else ++uintptr_t ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#endif ++{ ++ if (*refcook != -1 && *defcook != -1) ++ fprintf (stderr, "la_symbind: %s %u\n", symname, ++ *flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) ? 1 : 0); ++ return sym->st_value; ++} +diff --git a/sysdeps/generic/dl-lookupcfg.h b/sysdeps/generic/dl-lookupcfg.h +index e7d37170147aba83..7412c6391b0c3e02 100644 +--- a/sysdeps/generic/dl-lookupcfg.h ++++ b/sysdeps/generic/dl-lookupcfg.h +@@ -26,3 +26,6 @@ + #define DL_FIXUP_VALUE_CODE_ADDR(value) (value) + #define DL_FIXUP_VALUE_ADDR(value) (value) + #define DL_FIXUP_ADDR_VALUE(addr) (addr) ++#define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr) ++#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ (*value) = st_value; +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 73f4863fd43922b9..d4f70211c34d1c59 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1299,7 +1299,10 @@ void _dl_audit_objclose (struct link_map *l) + /* 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. */ ++/* Call the la_symbind{32,64} from the audit modules for the link_map L. If ++ RELOC_RESULT is NULL it assumes the symbol to be bind-now and will set ++ the flags with LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT prior calling ++ la_symbind{32,64}. */ + 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) +diff --git a/sysdeps/hppa/dl-lookupcfg.h b/sysdeps/hppa/dl-lookupcfg.h +index 38db345936cb6335..c3fea1fe5776b17a 100644 +--- a/sysdeps/hppa/dl-lookupcfg.h ++++ b/sysdeps/hppa/dl-lookupcfg.h +@@ -80,3 +80,6 @@ void attribute_hidden _dl_unmap (struct link_map *map); + #define DL_FIXUP_VALUE_CODE_ADDR(value) ((value).ip) + #define DL_FIXUP_VALUE_ADDR(value) ((uintptr_t) &(value)) + #define DL_FIXUP_ADDR_VALUE(addr) (*(struct fdesc *) (addr)) ++#define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr) ++#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ (*value) = *(struct fdesc *) (st_value) +diff --git a/sysdeps/ia64/dl-lookupcfg.h b/sysdeps/ia64/dl-lookupcfg.h +index 48f91202c43f8fda..97ad4b70794135a2 100644 +--- a/sysdeps/ia64/dl-lookupcfg.h ++++ b/sysdeps/ia64/dl-lookupcfg.h +@@ -74,3 +74,6 @@ extern void attribute_hidden _dl_unmap (struct link_map *map); + + #define DL_FIXUP_VALUE_ADDR(value) ((uintptr_t) &(value)) + #define DL_FIXUP_ADDR_VALUE(addr) (*(struct fdesc *) (addr)) ++#define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr) ++#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ (*value) = *(struct fdesc *) (st_value) +diff --git a/sysdeps/powerpc/dl-lookupcfg.h b/sysdeps/powerpc/dl-lookupcfg.h +new file mode 100644 +index 0000000000000000..25abcc1d12b15bfc +--- /dev/null ++++ b/sysdeps/powerpc/dl-lookupcfg.h +@@ -0,0 +1,39 @@ ++/* Configuration of lookup functions. PowerPC version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define DL_FIXUP_VALUE_TYPE ElfW(Addr) ++#define DL_FIXUP_MAKE_VALUE(map, addr) (addr) ++#define DL_FIXUP_VALUE_CODE_ADDR(value) (value) ++#define DL_FIXUP_VALUE_ADDR(value) (value) ++#define DL_FIXUP_ADDR_VALUE(addr) (addr) ++#if __WORDSIZE == 64 && _CALL_ELF == 1 ++/* We need to correctly set the audit modules value for bind-now. */ ++# define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) \ ++ (((Elf64_FuncDesc *)(addr))->fd_func) ++# define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ ({ \ ++ Elf64_FuncDesc *opd = (Elf64_FuncDesc *) (value); \ ++ opd->fd_func = (st_value); \ ++ if ((new_value) != (uintptr_t) (st_value)) \ ++ opd->fd_toc = ((Elf64_FuncDesc *)(new_value))->fd_toc; \ ++ }) ++#else ++# define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr) ++# define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ (*value) = st_value; ++#endif diff --git a/glibc-rh2047981-34.patch b/glibc-rh2047981-34.patch new file mode 100644 index 0000000..8809b82 --- /dev/null +++ b/glibc-rh2047981-34.patch @@ -0,0 +1,1042 @@ +commit ce9a68c57c260c8417afc93972849ac9ad243ec4 +Author: Ben Woodard +Date: Mon Jan 24 10:46:18 2022 -0300 + + elf: Fix runtime linker auditing on aarch64 (BZ #26643) + + The rtld audit support show two problems on aarch64: + + 1. _dl_runtime_resolve does not preserve x8, the indirect result + location register, which might generate wrong result calls + depending of the function signature. + + 2. The NEON Q registers pushed onto the stack by _dl_runtime_resolve + were twice the size of D registers extracted from the stack frame by + _dl_runtime_profile. + + While 2. might result in wrong information passed on the PLT tracing, + 1. generates wrong runtime behaviour. + + The aarch64 rtld audit support is changed to: + + * Both La_aarch64_regs and La_aarch64_retval are expanded to include + both x8 and the full sized NEON V registers, as defined by the + ABI. + + * dl_runtime_profile needed to extract registers saved by + _dl_runtime_resolve and put them into the new correctly sized + La_aarch64_regs structure. + + * The LAV_CURRENT check is change to only accept new audit modules + to avoid the undefined behavior of not save/restore x8. + + * Different than other architectures, audit modules older than + LAV_CURRENT are rejected (both La_aarch64_regs and La_aarch64_retval + changed their layout and there are no requirements to support multiple + audit interface with the inherent aarch64 issues). + + * A new field is also reserved on both La_aarch64_regs and + La_aarch64_retval to support variant pcs symbols. + + Similar to x86, a new La_aarch64_vector type to represent the NEON + register is added on the La_aarch64_regs (so each type can be accessed + directly). + + Since LAV_CURRENT was already bumped to support bind-now, there is + no need to increase it again. + + Checked on aarch64-linux-gnu. + + Co-authored-by: Adhemerval Zanella + Reviewed-by: Szabolcs Nagy + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + +Conflicts: + elf/rtld.c + sysdeps/aarch64/Makefile + Rewrite slightly for inclusion in elf/ testing. + +diff --git a/elf/rtld.c b/elf/rtld.c +index caa980dbda3d1a72..aee5ca357f66121e 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1002,7 +1003,7 @@ file=%s [%lu]; audit interface function la_version returned zero; ignored.\n", + return; + } + +- if (lav > LAV_CURRENT) ++ if (!_dl_audit_check_version (lav)) + { + _dl_debug_printf ("\ + ERROR: audit interface '%s' requires version %d (maximum supported version %d); ignored.\n", +diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile +index 3ec78fefc6dd5797..794ea7d13ae2737f 100644 +--- a/sysdeps/aarch64/Makefile ++++ b/sysdeps/aarch64/Makefile +@@ -4,6 +4,26 @@ ifeq ($(subdir),elf) + sysdep-dl-routines += tlsdesc dl-tlsdesc + gen-as-const-headers += dl-link.sym + ++tests += tst-audit26 \ ++ tst-audit27 ++ ++modules-names += \ ++ tst-audit26mod \ ++ tst-auditmod26 \ ++ tst-audit27mod \ ++ tst-auditmod27 ++ ++$(objpfx)tst-audit26: $(objpfx)tst-audit26mod.so \ ++ $(objpfx)tst-auditmod26.so ++LDFLAGS-tst-audit26 += -Wl,-z,lazy ++tst-audit26-ENV = LD_AUDIT=$(objpfx)tst-auditmod26.so ++ ++$(objpfx)tst-audit27: $(objpfx)tst-audit27mod.so \ ++ $(objpfx)tst-auditmod27.so ++$(objpfx)tst-audit27mod.so: $(libsupport) ++LDFLAGS-tst-audit27 += -Wl,-z,lazy ++tst-audit27-ENV = LD_AUDIT=$(objpfx)tst-auditmod27.so ++ + ifeq (yes,$(aarch64-variant-pcs)) + tests += tst-vpcs + modules-names += tst-vpcs-mod +diff --git a/sysdeps/aarch64/bits/link.h b/sysdeps/aarch64/bits/link.h +index 5a7fc1ccd494b2a7..f4f844bfefdaf2f5 100644 +--- a/sysdeps/aarch64/bits/link.h ++++ b/sysdeps/aarch64/bits/link.h +@@ -20,23 +20,31 @@ + # error "Never include directly; use instead." + #endif + ++typedef union ++{ ++ float s; ++ double d; ++ long double q; ++} La_aarch64_vector; ++ + /* Registers for entry into PLT on AArch64. */ + typedef struct La_aarch64_regs + { +- uint64_t lr_xreg[8]; +- uint64_t lr_dreg[8]; +- uint64_t lr_sp; +- uint64_t lr_lr; ++ uint64_t lr_xreg[9]; ++ La_aarch64_vector lr_vreg[8]; ++ uint64_t lr_sp; ++ uint64_t lr_lr; ++ void *lr_vpcs; + } La_aarch64_regs; + + /* Return values for calls from PLT on AArch64. */ + typedef struct La_aarch64_retval + { +- /* Up to two integer registers can be used for a return value. */ +- uint64_t lrv_xreg[2]; +- /* Up to four D registers can be used for a return value. */ +- uint64_t lrv_dreg[4]; +- ++ /* Up to eight integer registers can be used for a return value. */ ++ uint64_t lrv_xreg[8]; ++ /* Up to eight V registers can be used for a return value. */ ++ La_aarch64_vector lrv_vreg[8]; ++ void *lrv_vpcs; + } La_aarch64_retval; + __BEGIN_DECLS + +diff --git a/sysdeps/aarch64/dl-audit-check.h b/sysdeps/aarch64/dl-audit-check.h +new file mode 100644 +index 0000000000000000..e324339a1d4abec3 +--- /dev/null ++++ b/sysdeps/aarch64/dl-audit-check.h +@@ -0,0 +1,28 @@ ++/* rtld-audit version check. AArch64 version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++static inline bool ++_dl_audit_check_version (unsigned int lav) ++{ ++ /* Audit version 1 do not save x8 or NEON registers, which required ++ changing La_aarch64_regs and La_aarch64_retval layout (BZ#26643). The ++ missing indirect result save/restore makes _dl_runtime_profile ++ potentially trigger undefined behavior if the function returns a large ++ struct (even when PLT trace is not requested). */ ++ return lav == LAV_CURRENT; ++} +diff --git a/sysdeps/aarch64/dl-link.sym b/sysdeps/aarch64/dl-link.sym +index d67d28b40ce7d4ff..cb4dcdcbed0db492 100644 +--- a/sysdeps/aarch64/dl-link.sym ++++ b/sysdeps/aarch64/dl-link.sym +@@ -7,9 +7,11 @@ DL_SIZEOF_RG sizeof(struct La_aarch64_regs) + DL_SIZEOF_RV sizeof(struct La_aarch64_retval) + + DL_OFFSET_RG_X0 offsetof(struct La_aarch64_regs, lr_xreg) +-DL_OFFSET_RG_D0 offsetof(struct La_aarch64_regs, lr_dreg) ++DL_OFFSET_RG_V0 offsetof(struct La_aarch64_regs, lr_vreg) + DL_OFFSET_RG_SP offsetof(struct La_aarch64_regs, lr_sp) + DL_OFFSET_RG_LR offsetof(struct La_aarch64_regs, lr_lr) ++DL_OFFSET_RG_VPCS offsetof(struct La_aarch64_regs, lr_vpcs) + + DL_OFFSET_RV_X0 offsetof(struct La_aarch64_retval, lrv_xreg) +-DL_OFFSET_RV_D0 offsetof(struct La_aarch64_retval, lrv_dreg) ++DL_OFFSET_RV_V0 offsetof(struct La_aarch64_retval, lrv_vreg) ++DL_OFFSET_RV_VPCS offsetof(struct La_aarch64_retval, lrv_vpcs) +diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S +index 18740398e63fdf97..a83e7fc5f97047e2 100644 +--- a/sysdeps/aarch64/dl-trampoline.S ++++ b/sysdeps/aarch64/dl-trampoline.S +@@ -44,7 +44,8 @@ _dl_runtime_resolve: + + cfi_rel_offset (lr, 8) + +- /* Save arguments. */ ++ /* Note: Saving x9 is not required by the ABI but the assembler requires ++ the immediate values of operand 3 to be a multiple of 16 */ + stp x8, x9, [sp, #-(80+8*16)]! + cfi_adjust_cfa_offset (80+8*16) + cfi_rel_offset (x8, 0) +@@ -135,7 +136,7 @@ _dl_runtime_profile: + Stack frame layout: + [sp, #...] lr + [sp, #...] &PLTGOT[n] +- [sp, #96] La_aarch64_regs ++ [sp, #256] La_aarch64_regs + [sp, #48] La_aarch64_retval + [sp, #40] frame size return from pltenter + [sp, #32] dl_profile_call saved x1 +@@ -176,19 +177,25 @@ _dl_runtime_profile: + stp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] + cfi_rel_offset (x6, OFFSET_RG + DL_OFFSET_RG_X0 + 16*3 + 0) + cfi_rel_offset (x7, OFFSET_RG + DL_OFFSET_RG_X0 + 16*3 + 8) +- +- stp d0, d1, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0] +- cfi_rel_offset (d0, OFFSET_RG + DL_OFFSET_RG_D0 + 16*0) +- cfi_rel_offset (d1, OFFSET_RG + DL_OFFSET_RG_D0 + 16*0 + 8) +- stp d2, d3, [X29, #OFFSET_RG+ DL_OFFSET_RG_D0 + 16*1] +- cfi_rel_offset (d2, OFFSET_RG + DL_OFFSET_RG_D0 + 16*1 + 0) +- cfi_rel_offset (d3, OFFSET_RG + DL_OFFSET_RG_D0 + 16*1 + 8) +- stp d4, d5, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2] +- cfi_rel_offset (d4, OFFSET_RG + DL_OFFSET_RG_D0 + 16*2 + 0) +- cfi_rel_offset (d5, OFFSET_RG + DL_OFFSET_RG_D0 + 16*2 + 8) +- stp d6, d7, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3] +- cfi_rel_offset (d6, OFFSET_RG + DL_OFFSET_RG_D0 + 16*3 + 0) +- cfi_rel_offset (d7, OFFSET_RG + DL_OFFSET_RG_D0 + 16*3 + 8) ++ str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4 + 0] ++ cfi_rel_offset (x8, OFFSET_RG + DL_OFFSET_RG_X0 + 16*4 + 0) ++ /* Note 8 bytes of padding is in the stack frame for alignment */ ++ ++ stp q0, q1, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0] ++ cfi_rel_offset (q0, OFFSET_RG + DL_OFFSET_RG_V0 + 32*0) ++ cfi_rel_offset (q1, OFFSET_RG + DL_OFFSET_RG_V0 + 32*0 + 16) ++ stp q2, q3, [X29, #OFFSET_RG+ DL_OFFSET_RG_V0 + 32*1] ++ cfi_rel_offset (q2, OFFSET_RG + DL_OFFSET_RG_V0 + 32*1 + 0) ++ cfi_rel_offset (q3, OFFSET_RG + DL_OFFSET_RG_V0 + 32*1 + 16) ++ stp q4, q5, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2] ++ cfi_rel_offset (q4, OFFSET_RG + DL_OFFSET_RG_V0 + 32*2 + 0) ++ cfi_rel_offset (q5, OFFSET_RG + DL_OFFSET_RG_V0 + 32*2 + 16) ++ stp q6, q7, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3] ++ cfi_rel_offset (q6, OFFSET_RG + DL_OFFSET_RG_V0 + 32*3 + 0) ++ cfi_rel_offset (q7, OFFSET_RG + DL_OFFSET_RG_V0 + 32*3 + 16) ++ ++ /* No APCS extension supported. */ ++ str xzr, [X29, #OFFSET_RG + DL_OFFSET_RG_VPCS] + + add x0, x29, #SF_SIZE + 16 + ldr x1, [x29, #OFFSET_LR] +@@ -227,10 +234,11 @@ _dl_runtime_profile: + ldp x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1] + ldp x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2] + ldp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] +- ldp d0, d1, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0] +- ldp d2, d3, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*1] +- ldp d4, d5, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2] +- ldp d6, d7, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3] ++ ldr x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] ++ ldp q0, q1, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0] ++ ldp q2, q3, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*1] ++ ldp q4, q5, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2] ++ ldp q6, q7, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3] + + cfi_def_cfa_register (sp) + ldp x29, x30, [x29, #0] +@@ -264,14 +272,22 @@ _dl_runtime_profile: + ldp x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1] + ldp x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2] + ldp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] +- ldp d0, d1, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0] +- ldp d2, d3, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*1] +- ldp d4, d5, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2] +- ldp d6, d7, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3] ++ ldr x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] ++ ldp q0, q1, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0] ++ ldp q2, q3, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*1] ++ ldp q4, q5, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2] ++ ldp q6, q7, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3] + blr ip0 +- stp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0] +- stp d0, d1, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*0] +- stp d2, d3, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*1] ++ stp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*0] ++ stp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] ++ stp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] ++ stp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] ++ str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] ++ stp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] ++ stp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] ++ stp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] ++ stp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] ++ str xzr, [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS] + + /* Setup call to pltexit */ + ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0] +@@ -279,9 +295,16 @@ _dl_runtime_profile: + add x3, x29, #OFFSET_RV + 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] +- ldp d2, d3, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*1] ++ ldp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*0] ++ ldp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] ++ ldp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] ++ ldp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] ++ ldr x8, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4] ++ ldp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] ++ ldp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] ++ ldp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] ++ ldp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] ++ + /* LR from within La_aarch64_reg */ + ldr lr, [x29, #OFFSET_RG + DL_OFFSET_RG_LR] + cfi_restore(lr) +diff --git a/sysdeps/aarch64/tst-audit26.c b/sysdeps/aarch64/tst-audit26.c +new file mode 100644 +index 0000000000000000..46de8acd219cb8bc +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit26.c +@@ -0,0 +1,37 @@ ++/* Check LD_AUDIT for aarch64 ABI specifics. ++ 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 "tst-audit26mod.h" ++ ++int ++do_test (void) ++{ ++ /* Returning a large struct uses 'x8' as indirect result location. */ ++ struct large_struct r = tst_audit26_func (ARG1, ARG2, ARG3); ++ ++ struct large_struct e = set_large_struct (ARG1, ARG2, ARG3); ++ ++ TEST_COMPARE_BLOB (r.a, sizeof (r.a), e.a, sizeof (e.a)); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/aarch64/tst-audit26mod.c b/sysdeps/aarch64/tst-audit26mod.c +new file mode 100644 +index 0000000000000000..67d5ffce7288b34c +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit26mod.c +@@ -0,0 +1,33 @@ ++/* Check LD_AUDIT for aarch64 ABI specifics. ++ 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 "tst-audit26mod.h" ++ ++struct large_struct ++tst_audit26_func (char a, short b, long int c) ++{ ++ if (a != ARG1) ++ abort (); ++ if (b != ARG2) ++ abort (); ++ if (c != ARG3) ++ abort (); ++ ++ return set_large_struct (a, b, c); ++} +diff --git a/sysdeps/aarch64/tst-audit26mod.h b/sysdeps/aarch64/tst-audit26mod.h +new file mode 100644 +index 0000000000000000..f80409f96bae6c82 +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit26mod.h +@@ -0,0 +1,50 @@ ++/* Check LD_AUDIT for aarch64 specific ABI. ++ 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 ++ . */ ++ ++#ifndef _TST_AUDIT27MOD_H ++#define _TST_AUDIT27MOD_H 1 ++ ++#include ++ ++struct large_struct ++{ ++ char a[16]; ++ short b[8]; ++ long int c[4]; ++}; ++ ++static inline struct large_struct ++set_large_struct (char a, short b, long int c) ++{ ++ struct large_struct r; ++ for (int i = 0; i < array_length (r.a); i++) ++ r.a[i] = a; ++ for (int i = 0; i < array_length (r.b); i++) ++ r.b[i] = b; ++ for (int i = 0; i < array_length (r.c); i++) ++ r.c[i] = c; ++ return r; ++} ++ ++#define ARG1 0x12 ++#define ARG2 0x1234 ++#define ARG3 0x12345678 ++ ++struct large_struct tst_audit26_func (char a, short b, long int c); ++ ++#endif +diff --git a/sysdeps/aarch64/tst-audit27.c b/sysdeps/aarch64/tst-audit27.c +new file mode 100644 +index 0000000000000000..5ebc09771f845af0 +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit27.c +@@ -0,0 +1,64 @@ ++/* Check LD_AUDIT for aarch64 ABI specifics. ++ 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 "tst-audit27mod.h" ++ ++int ++do_test (void) ++{ ++ { ++ float r = tst_audit27_func_float (FUNC_FLOAT_ARG0, FUNC_FLOAT_ARG1, ++ FUNC_FLOAT_ARG2, FUNC_FLOAT_ARG3, ++ FUNC_FLOAT_ARG4, FUNC_FLOAT_ARG5, ++ FUNC_FLOAT_ARG6, FUNC_FLOAT_ARG7); ++ if (r != FUNC_FLOAT_RET) ++ FAIL_EXIT1 ("tst_audit27_func_float() returned %a, expected %a", ++ r, FUNC_FLOAT_RET); ++ } ++ ++ { ++ double r = tst_audit27_func_double (FUNC_DOUBLE_ARG0, FUNC_DOUBLE_ARG1, ++ FUNC_DOUBLE_ARG2, FUNC_DOUBLE_ARG3, ++ FUNC_DOUBLE_ARG4, FUNC_DOUBLE_ARG5, ++ FUNC_DOUBLE_ARG6, FUNC_DOUBLE_ARG7); ++ if (r != FUNC_DOUBLE_RET) ++ FAIL_EXIT1 ("tst_audit27_func_double() returned %la, expected %la", ++ r, FUNC_DOUBLE_RET); ++ } ++ ++ { ++ long double r = tst_audit27_func_ldouble (FUNC_LDOUBLE_ARG0, ++ FUNC_LDOUBLE_ARG1, ++ FUNC_LDOUBLE_ARG2, ++ FUNC_LDOUBLE_ARG3, ++ FUNC_LDOUBLE_ARG4, ++ FUNC_LDOUBLE_ARG5, ++ FUNC_LDOUBLE_ARG6, ++ FUNC_LDOUBLE_ARG7); ++ if (r != FUNC_LDOUBLE_RET) ++ FAIL_EXIT1 ("tst_audit27_func_ldouble() returned %La, expected %La", ++ r, FUNC_LDOUBLE_RET); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/aarch64/tst-audit27mod.c b/sysdeps/aarch64/tst-audit27mod.c +new file mode 100644 +index 0000000000000000..922b518f0af4b97b +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit27mod.c +@@ -0,0 +1,95 @@ ++/* Check LD_AUDIT for aarch64 ABI specifics. ++ 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 "tst-audit27mod.h" ++ ++float ++tst_audit27_func_float (float a0, float a1, float a2, float a3, float a4, ++ float a5, float a6, float a7) ++{ ++ if (a0 != FUNC_FLOAT_ARG0) ++ FAIL_EXIT1 ("a0: %a != %a", a0, FUNC_FLOAT_ARG0); ++ if (a1 != FUNC_FLOAT_ARG1) ++ FAIL_EXIT1 ("a1: %a != %a", a1, FUNC_FLOAT_ARG1); ++ if (a2 != FUNC_FLOAT_ARG2) ++ FAIL_EXIT1 ("a2: %a != %a", a2, FUNC_FLOAT_ARG2); ++ if (a3 != FUNC_FLOAT_ARG3) ++ FAIL_EXIT1 ("a3: %a != %a", a3, FUNC_FLOAT_ARG3); ++ if (a4 != FUNC_FLOAT_ARG4) ++ FAIL_EXIT1 ("a4: %a != %a", a4, FUNC_FLOAT_ARG4); ++ if (a5 != FUNC_FLOAT_ARG5) ++ FAIL_EXIT1 ("a5: %a != %a", a5, FUNC_FLOAT_ARG5); ++ if (a6 != FUNC_FLOAT_ARG6) ++ FAIL_EXIT1 ("a6: %a != %a", a6, FUNC_FLOAT_ARG6); ++ if (a7 != FUNC_FLOAT_ARG7) ++ FAIL_EXIT1 ("a7: %a != %a", a7, FUNC_FLOAT_ARG7); ++ ++ return FUNC_FLOAT_RET; ++} ++ ++double ++tst_audit27_func_double (double a0, double a1, double a2, double a3, double a4, ++ double a5, double a6, double a7) ++{ ++ if (a0 != FUNC_DOUBLE_ARG0) ++ FAIL_EXIT1 ("a0: %la != %la", a0, FUNC_DOUBLE_ARG0); ++ if (a1 != FUNC_DOUBLE_ARG1) ++ FAIL_EXIT1 ("a1: %la != %la", a1, FUNC_DOUBLE_ARG1); ++ if (a2 != FUNC_DOUBLE_ARG2) ++ FAIL_EXIT1 ("a2: %la != %la", a2, FUNC_DOUBLE_ARG2); ++ if (a3 != FUNC_DOUBLE_ARG3) ++ FAIL_EXIT1 ("a3: %la != %la", a3, FUNC_DOUBLE_ARG3); ++ if (a4 != FUNC_DOUBLE_ARG4) ++ FAIL_EXIT1 ("a4: %la != %la", a4, FUNC_DOUBLE_ARG4); ++ if (a5 != FUNC_DOUBLE_ARG5) ++ FAIL_EXIT1 ("a5: %la != %la", a5, FUNC_DOUBLE_ARG5); ++ if (a6 != FUNC_DOUBLE_ARG6) ++ FAIL_EXIT1 ("a6: %la != %la", a6, FUNC_DOUBLE_ARG6); ++ if (a7 != FUNC_DOUBLE_ARG7) ++ FAIL_EXIT1 ("a7: %la != %la", a7, FUNC_DOUBLE_ARG7); ++ ++ return FUNC_DOUBLE_RET; ++} ++ ++long double ++tst_audit27_func_ldouble (long double a0, long double a1, long double a2, ++ long double a3, long double a4, long double a5, ++ long double a6, long double a7) ++{ ++ if (a0 != FUNC_LDOUBLE_ARG0) ++ FAIL_EXIT1 ("a0: %La != %La", a0, FUNC_LDOUBLE_ARG0); ++ if (a1 != FUNC_LDOUBLE_ARG1) ++ FAIL_EXIT1 ("a1: %La != %La", a1, FUNC_LDOUBLE_ARG1); ++ if (a2 != FUNC_LDOUBLE_ARG2) ++ FAIL_EXIT1 ("a2: %La != %La", a2, FUNC_LDOUBLE_ARG2); ++ if (a3 != FUNC_LDOUBLE_ARG3) ++ FAIL_EXIT1 ("a3: %La != %La", a3, FUNC_LDOUBLE_ARG3); ++ if (a4 != FUNC_LDOUBLE_ARG4) ++ FAIL_EXIT1 ("a4: %La != %La", a4, FUNC_LDOUBLE_ARG4); ++ if (a5 != FUNC_LDOUBLE_ARG5) ++ FAIL_EXIT1 ("a5: %La != %La", a5, FUNC_LDOUBLE_ARG5); ++ if (a6 != FUNC_LDOUBLE_ARG6) ++ FAIL_EXIT1 ("a6: %La != %La", a6, FUNC_LDOUBLE_ARG6); ++ if (a7 != FUNC_LDOUBLE_ARG7) ++ FAIL_EXIT1 ("a7: %La != %La", a7, FUNC_LDOUBLE_ARG7); ++ ++ return FUNC_LDOUBLE_RET; ++} +diff --git a/sysdeps/aarch64/tst-audit27mod.h b/sysdeps/aarch64/tst-audit27mod.h +new file mode 100644 +index 0000000000000000..1709d222ca251e3b +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit27mod.h +@@ -0,0 +1,67 @@ ++/* Check LD_AUDIT for aarch64 specific ABI. ++ 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 ++ . */ ++ ++#ifndef _TST_AUDIT27MOD_H ++#define _TST_AUDIT27MOD_H 1 ++ ++#include ++ ++#define FUNC_FLOAT_ARG0 FLT_MIN ++#define FUNC_FLOAT_ARG1 FLT_MAX ++#define FUNC_FLOAT_ARG2 FLT_EPSILON ++#define FUNC_FLOAT_ARG3 FLT_TRUE_MIN ++#define FUNC_FLOAT_ARG4 0.0f ++#define FUNC_FLOAT_ARG5 1.0f ++#define FUNC_FLOAT_ARG6 2.0f ++#define FUNC_FLOAT_ARG7 3.0f ++#define FUNC_FLOAT_RET 4.0f ++ ++float ++tst_audit27_func_float (float a0, float a1, float a2, float a3, float a4, ++ float a5, float a6, float a7); ++ ++#define FUNC_DOUBLE_ARG0 DBL_MIN ++#define FUNC_DOUBLE_ARG1 DBL_MAX ++#define FUNC_DOUBLE_ARG2 DBL_EPSILON ++#define FUNC_DOUBLE_ARG3 DBL_TRUE_MIN ++#define FUNC_DOUBLE_ARG4 0.0 ++#define FUNC_DOUBLE_ARG5 1.0 ++#define FUNC_DOUBLE_ARG6 2.0 ++#define FUNC_DOUBLE_ARG7 3.0 ++#define FUNC_DOUBLE_RET 0x1.fffffe0000001p+127 ++ ++double ++tst_audit27_func_double (double a0, double a1, double a2, double a3, double a4, ++ double a5, double a6, double a7); ++ ++#define FUNC_LDOUBLE_ARG0 DBL_MAX + 1.0L ++#define FUNC_LDOUBLE_ARG1 DBL_MAX + 2.0L ++#define FUNC_LDOUBLE_ARG2 DBL_MAX + 3.0L ++#define FUNC_LDOUBLE_ARG3 DBL_MAX + 4.0L ++#define FUNC_LDOUBLE_ARG4 DBL_MAX + 5.0L ++#define FUNC_LDOUBLE_ARG5 DBL_MAX + 6.0L ++#define FUNC_LDOUBLE_ARG6 DBL_MAX + 7.0L ++#define FUNC_LDOUBLE_ARG7 DBL_MAX + 8.0L ++#define FUNC_LDOUBLE_RET 0x1.fffffffffffff000000000000001p+1023L ++ ++long double ++tst_audit27_func_ldouble (long double a0, long double a1, long double a2, ++ long double a3, long double a4, long double a5, ++ long double a6, long double a7); ++ ++#endif +diff --git a/sysdeps/aarch64/tst-auditmod26.c b/sysdeps/aarch64/tst-auditmod26.c +new file mode 100644 +index 0000000000000000..b03b6baed9aeb528 +--- /dev/null ++++ b/sysdeps/aarch64/tst-auditmod26.c +@@ -0,0 +1,103 @@ ++/* Check LD_AUDIT for aarch64 specific ABI. ++ 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 "tst-audit26mod.h" ++ ++#define TEST_NAME "tst-audit26" ++ ++#define AUDIT26_COOKIE 0 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ return v; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? map->l_name : p + 1; ++ uintptr_t ck = -1; ++ if (strncmp (l_name, TEST_NAME, strlen (TEST_NAME)) == 0) ++ ck = AUDIT26_COOKIE; ++ *cookie = ck; ++ printf ("objopen: %ld, %s [cookie=%ld]\n", lmid, l_name, ck); ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++ElfW(Addr) ++la_aarch64_gnu_pltenter (ElfW(Sym) *sym __attribute__ ((unused)), ++ unsigned int ndx __attribute__ ((unused)), ++ uintptr_t *refcook, uintptr_t *defcook, ++ La_aarch64_regs *regs, unsigned int *flags, ++ const char *symname, long int *framesizep) ++{ ++ printf ("pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n", ++ symname, (long int) sym->st_value, ndx, *flags); ++ ++ if (strcmp (symname, "tst_audit26_func") == 0) ++ { ++ assert (regs->lr_xreg[0] == ARG1); ++ assert (regs->lr_xreg[1] == ARG2); ++ assert (regs->lr_xreg[2] == ARG3); ++ } ++ else ++ abort (); ++ ++ assert (regs->lr_vpcs == 0); ++ ++ /* Clobber 'x8'. */ ++ asm volatile ("mov x8, -1" : : : "x8"); ++ ++ *framesizep = 1024; ++ ++ return sym->st_value; ++} ++ ++unsigned int ++la_aarch64_gnu_pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, ++ const struct La_aarch64_regs *inregs, ++ struct La_aarch64_retval *outregs, const char *symname) ++{ ++ printf ("pltexit: symname=%s, st_value=%#lx, ndx=%u\n", ++ symname, (long int) sym->st_value, ndx); ++ ++ if (strcmp (symname, "tst_audit26_func") == 0) ++ { ++ assert (inregs->lr_xreg[0] == ARG1); ++ assert (inregs->lr_xreg[1] == ARG2); ++ assert (inregs->lr_xreg[2] == ARG3); ++ } ++ else ++ abort (); ++ ++ assert (inregs->lr_vpcs == 0); ++ assert (outregs->lrv_vpcs == 0); ++ ++ /* Clobber 'x8'. */ ++ asm volatile ("mov x8, -1" : : : "x8"); ++ ++ return 0; ++} +diff --git a/sysdeps/aarch64/tst-auditmod27.c b/sysdeps/aarch64/tst-auditmod27.c +new file mode 100644 +index 0000000000000000..21132c2985dab7b2 +--- /dev/null ++++ b/sysdeps/aarch64/tst-auditmod27.c +@@ -0,0 +1,180 @@ ++/* Check LD_AUDIT for aarch64 specific ABI. ++ 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 "tst-audit27mod.h" ++ ++#define TEST_NAME "tst-audit27" ++ ++#define AUDIT27_COOKIE 0 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ return v; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? map->l_name : p + 1; ++ uintptr_t ck = -1; ++ if (strncmp (l_name, TEST_NAME, strlen (TEST_NAME)) == 0) ++ ck = AUDIT27_COOKIE; ++ *cookie = ck; ++ printf ("objopen: %ld, %s [%ld]\n", lmid, l_name, ck); ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++ElfW(Addr) ++la_aarch64_gnu_pltenter (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, La_aarch64_regs *regs, ++ unsigned int *flags, const char *symname, ++ long int *framesizep) ++{ ++ printf ("pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n", ++ symname, (long int) sym->st_value, ndx, *flags); ++ ++ if (strcmp (symname, "tst_audit27_func_float") == 0) ++ { ++ assert (regs->lr_vreg[0].s == FUNC_FLOAT_ARG0); ++ assert (regs->lr_vreg[1].s == FUNC_FLOAT_ARG1); ++ assert (regs->lr_vreg[2].s == FUNC_FLOAT_ARG2); ++ assert (regs->lr_vreg[3].s == FUNC_FLOAT_ARG3); ++ assert (regs->lr_vreg[4].s == FUNC_FLOAT_ARG4); ++ assert (regs->lr_vreg[5].s == FUNC_FLOAT_ARG5); ++ assert (regs->lr_vreg[6].s == FUNC_FLOAT_ARG6); ++ assert (regs->lr_vreg[7].s == FUNC_FLOAT_ARG7); ++ } ++ else if (strcmp (symname, "tst_audit27_func_double") == 0) ++ { ++ assert (regs->lr_vreg[0].d == FUNC_DOUBLE_ARG0); ++ assert (regs->lr_vreg[1].d == FUNC_DOUBLE_ARG1); ++ assert (regs->lr_vreg[2].d == FUNC_DOUBLE_ARG2); ++ assert (regs->lr_vreg[3].d == FUNC_DOUBLE_ARG3); ++ assert (regs->lr_vreg[4].d == FUNC_DOUBLE_ARG4); ++ assert (regs->lr_vreg[5].d == FUNC_DOUBLE_ARG5); ++ assert (regs->lr_vreg[6].d == FUNC_DOUBLE_ARG6); ++ assert (regs->lr_vreg[7].d == FUNC_DOUBLE_ARG7); ++ } ++ else if (strcmp (symname, "tst_audit27_func_ldouble") == 0) ++ { ++ assert (regs->lr_vreg[0].q == FUNC_LDOUBLE_ARG0); ++ assert (regs->lr_vreg[1].q == FUNC_LDOUBLE_ARG1); ++ assert (regs->lr_vreg[2].q == FUNC_LDOUBLE_ARG2); ++ assert (regs->lr_vreg[3].q == FUNC_LDOUBLE_ARG3); ++ assert (regs->lr_vreg[4].q == FUNC_LDOUBLE_ARG4); ++ assert (regs->lr_vreg[5].q == FUNC_LDOUBLE_ARG5); ++ assert (regs->lr_vreg[6].q == FUNC_LDOUBLE_ARG6); ++ assert (regs->lr_vreg[7].q == FUNC_LDOUBLE_ARG7); ++ } ++ else ++ abort (); ++ ++ assert (regs->lr_vpcs == 0); ++ ++ /* Clobber the q registers on exit. */ ++ uint8_t v = 0xff; ++ asm volatile ("dup v0.8b, %w0" : : "r" (v) : "v0"); ++ asm volatile ("dup v1.8b, %w0" : : "r" (v) : "v1"); ++ asm volatile ("dup v2.8b, %w0" : : "r" (v) : "v2"); ++ asm volatile ("dup v3.8b, %w0" : : "r" (v) : "v3"); ++ asm volatile ("dup v4.8b, %w0" : : "r" (v) : "v4"); ++ asm volatile ("dup v5.8b, %w0" : : "r" (v) : "v5"); ++ asm volatile ("dup v6.8b, %w0" : : "r" (v) : "v6"); ++ asm volatile ("dup v7.8b, %w0" : : "r" (v) : "v7"); ++ ++ *framesizep = 1024; ++ ++ return sym->st_value; ++} ++ ++unsigned int ++la_aarch64_gnu_pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, ++ const struct La_aarch64_regs *inregs, ++ struct La_aarch64_retval *outregs, ++ const char *symname) ++{ ++ printf ("pltexit: symname=%s, st_value=%#lx, ndx=%u\n", ++ symname, (long int) sym->st_value, ndx); ++ ++ if (strcmp (symname, "tst_audit27_func_float") == 0) ++ { ++ assert (inregs->lr_vreg[0].s == FUNC_FLOAT_ARG0); ++ assert (inregs->lr_vreg[1].s == FUNC_FLOAT_ARG1); ++ assert (inregs->lr_vreg[2].s == FUNC_FLOAT_ARG2); ++ assert (inregs->lr_vreg[3].s == FUNC_FLOAT_ARG3); ++ assert (inregs->lr_vreg[4].s == FUNC_FLOAT_ARG4); ++ assert (inregs->lr_vreg[5].s == FUNC_FLOAT_ARG5); ++ assert (inregs->lr_vreg[6].s == FUNC_FLOAT_ARG6); ++ assert (inregs->lr_vreg[7].s == FUNC_FLOAT_ARG7); ++ ++ assert (outregs->lrv_vreg[0].s == FUNC_FLOAT_RET); ++ } ++ else if (strcmp (symname, "tst_audit27_func_double") == 0) ++ { ++ assert (inregs->lr_vreg[0].d == FUNC_DOUBLE_ARG0); ++ assert (inregs->lr_vreg[1].d == FUNC_DOUBLE_ARG1); ++ assert (inregs->lr_vreg[2].d == FUNC_DOUBLE_ARG2); ++ assert (inregs->lr_vreg[3].d == FUNC_DOUBLE_ARG3); ++ assert (inregs->lr_vreg[4].d == FUNC_DOUBLE_ARG4); ++ assert (inregs->lr_vreg[5].d == FUNC_DOUBLE_ARG5); ++ assert (inregs->lr_vreg[6].d == FUNC_DOUBLE_ARG6); ++ assert (inregs->lr_vreg[7].d == FUNC_DOUBLE_ARG7); ++ ++ assert (outregs->lrv_vreg[0].d == FUNC_DOUBLE_RET); ++ } ++ else if (strcmp (symname, "tst_audit27_func_ldouble") == 0) ++ { ++ assert (inregs->lr_vreg[0].q == FUNC_LDOUBLE_ARG0); ++ assert (inregs->lr_vreg[1].q == FUNC_LDOUBLE_ARG1); ++ assert (inregs->lr_vreg[2].q == FUNC_LDOUBLE_ARG2); ++ assert (inregs->lr_vreg[3].q == FUNC_LDOUBLE_ARG3); ++ assert (inregs->lr_vreg[4].q == FUNC_LDOUBLE_ARG4); ++ assert (inregs->lr_vreg[5].q == FUNC_LDOUBLE_ARG5); ++ assert (inregs->lr_vreg[6].q == FUNC_LDOUBLE_ARG6); ++ assert (inregs->lr_vreg[7].q == FUNC_LDOUBLE_ARG7); ++ ++ assert (outregs->lrv_vreg[0].q == FUNC_LDOUBLE_RET); ++ } ++ else ++ abort (); ++ ++ assert (inregs->lr_vpcs == 0); ++ assert (outregs->lrv_vpcs == 0); ++ ++ /* Clobber the q registers on exit. */ ++ uint8_t v = 0xff; ++ asm volatile ("dup v0.8b, %w0" : : "r" (v) : "v0"); ++ asm volatile ("dup v1.8b, %w0" : : "r" (v) : "v1"); ++ asm volatile ("dup v2.8b, %w0" : : "r" (v) : "v2"); ++ asm volatile ("dup v3.8b, %w0" : : "r" (v) : "v3"); ++ asm volatile ("dup v4.8b, %w0" : : "r" (v) : "v4"); ++ asm volatile ("dup v5.8b, %w0" : : "r" (v) : "v5"); ++ asm volatile ("dup v6.8b, %w0" : : "r" (v) : "v6"); ++ asm volatile ("dup v7.8b, %w0" : : "r" (v) : "v7"); ++ ++ return 0; ++} +diff --git a/sysdeps/generic/dl-audit-check.h b/sysdeps/generic/dl-audit-check.h +new file mode 100644 +index 0000000000000000..3ab76532868b5895 +--- /dev/null ++++ b/sysdeps/generic/dl-audit-check.h +@@ -0,0 +1,23 @@ ++/* rtld-audit version check. Generic version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++static inline bool ++_dl_audit_check_version (unsigned int lav) ++{ ++ return lav <= LAV_CURRENT; ++} diff --git a/glibc-rh2047981-35.patch b/glibc-rh2047981-35.patch new file mode 100644 index 0000000..92ecdc6 --- /dev/null +++ b/glibc-rh2047981-35.patch @@ -0,0 +1,21 @@ +commit 80a08d0faa9b224019f895800c4d97de4e23e1aa +Author: Szabolcs Nagy +Date: Wed Feb 2 14:03:58 2022 +0000 + + Fix elf/tst-audit25a with default bind now toolchains + + This test relies on lazy binding for the executable so request that + explicitly in case the toolchain defaults to bind now. + +diff --git a/elf/Makefile b/elf/Makefile +index 78147ed2dbcaf4c0..4d16ed1637db8582 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -2130,6 +2130,7 @@ $(objpfx)tst-audit25a: $(objpfx)tst-audit25mod1.so \ + $(objpfx)tst-audit25mod2.so \ + $(objpfx)tst-audit25mod3.so \ + $(objpfx)tst-audit25mod4.so ++LDFLAGS-tst-audit25a = -Wl,-z,lazy + $(objpfx)tst-audit25mod1.so: $(objpfx)tst-audit25mod3.so + LDFLAGS-tst-audit25mod1.so = -Wl,-z,now + $(objpfx)tst-audit25mod2.so: $(objpfx)tst-audit25mod4.so diff --git a/glibc-rh2047981-36.patch b/glibc-rh2047981-36.patch new file mode 100644 index 0000000..ceaec72 --- /dev/null +++ b/glibc-rh2047981-36.patch @@ -0,0 +1,28 @@ +commit fa7ad1df1915c8a62f50e3a5b7e10f9c7118cd7f +Author: H.J. Lu +Date: Sun Feb 6 11:12:24 2022 -0800 + + elf: Replace tst-audit24bmod2.so with tst-audit24bmod2 + + Replace tst-audit24bmod2.so with tst-audit24bmod2 to silence: + + make[2]: Entering directory '/export/gnu/import/git/gitlab/x86-glibc/elf' + Makefile:2201: warning: overriding recipe for target '/export/build/gnu/tools-build/glibc-gitlab/build-x86_64-linux/elf/tst-audit24bmod2.so' + ../Makerules:765: warning: ignoring old recipe for target '/export/build/gnu/tools-build/glibc-gitlab/build-x86_64-linux/elf/tst-audit24bmod2.so' + +Conflicts: + elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index 4d16ed1637db8582..73d347339762fc9e 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -855,7 +855,7 @@ extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) + + # filtmod1.so has a special rule + modules-names-nobuild := filtmod1 \ +- tst-audit24bmod1 tst-audit24bmod2.so ++ tst-audit24bmod1 tst-audit24bmod2 + + tests += $(tests-static) + diff --git a/glibc-rh2047981-37.patch b/glibc-rh2047981-37.patch new file mode 100644 index 0000000..8591468 --- /dev/null +++ b/glibc-rh2047981-37.patch @@ -0,0 +1,112 @@ +commit 9e94f57484a2aba0fe67ea2059b5843f651887c2 +Author: Adhemerval Zanella +Date: Fri Feb 4 15:54:59 2022 -0300 + + hppa: Fix bind-now audit (BZ #28857) + + On hppa, a function pointer returned by la_symbind is actually a function + descriptor has the plabel bit set (bit 30). This must be cleared to get + the actual address of the descriptor. If the descriptor has been bound, + the first word of the descriptor is the physical address of theA function, + otherwise, the first word of the descriptor points to a trampoline in the + PLT. + + This patch also adds a workaround on tests because on hppa (and it seems + to be the only ABI I have see it), some shared library adds a dynamic PLT + relocation to am empty symbol name: + + $ readelf -r elf/tst-audit25mod1.so + [...] + Relocation section '.rela.plt' at offset 0x464 contains 6 entries: + Offset Info Type Sym.Value Sym. Name + Addend + 00002008 00000081 R_PARISC_IPLT 508 + [...] + + It breaks some assumptions on the test, where a symbol with an empty + name ("") is passed on la_symbind. + + Checked on x86_64-linux-gnu and hppa-linux-gnu. + +diff --git a/elf/Makefile b/elf/Makefile +index 73d347339762fc9e..6d39b400060a73f3 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -2113,7 +2113,7 @@ $(objpfx)tst-audit24c.out: $(objpfx)tst-auditmod24c.so + $(objpfx)tst-audit24c: $(objpfx)tst-audit24amod1.so \ + $(objpfx)tst-audit24amod2.so + tst-audit24c-ENV = LD_BIND_NOW=1 LD_AUDIT=$(objpfx)tst-auditmod24c.so +-LDFLAGS-tst-audit24b = -Wl,-z,lazy ++LDFLAGS-tst-audit24c = -Wl,-z,lazy + + $(objpfx)tst-audit24d.out: $(objpfx)tst-auditmod24d.so + $(objpfx)tst-audit24d: $(objpfx)tst-audit24dmod1.so \ +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index 72a50717ef60a357..ec9b032eae37c103 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -257,7 +257,8 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + reloc_result->flags = flags; + } + +- DL_FIXUP_BINDNOW_RELOC (value, new_value, sym.st_value); ++ if (flags & LA_SYMB_ALTVALUE) ++ DL_FIXUP_BINDNOW_RELOC (value, new_value, sym.st_value); + } + + void +diff --git a/elf/tst-auditmod24a.c b/elf/tst-auditmod24a.c +index d8e88f3984af1707..3075dfae2fd3d288 100644 +--- a/elf/tst-auditmod24a.c ++++ b/elf/tst-auditmod24a.c +@@ -110,5 +110,7 @@ la_symbind32 (Elf32_Sym *sym, unsigned int ndx, + return sym->st_value; + } + +- abort (); ++ if (symname[0] != '\0') ++ abort (); ++ return sym->st_value; + } +diff --git a/elf/tst-auditmod24d.c b/elf/tst-auditmod24d.c +index 8c803ecc0a48f21b..badc6be451ee0357 100644 +--- a/elf/tst-auditmod24d.c ++++ b/elf/tst-auditmod24d.c +@@ -116,5 +116,7 @@ la_symbind32 (Elf32_Sym *sym, unsigned int ndx, + } + } + +- abort (); ++ if (symname[0] != '\0') ++ abort (); ++ return sym->st_value; + } +diff --git a/elf/tst-auditmod25.c b/elf/tst-auditmod25.c +index 526f5c54bc2c3b8c..20640a8daf346b5f 100644 +--- a/elf/tst-auditmod25.c ++++ b/elf/tst-auditmod25.c +@@ -72,7 +72,7 @@ la_symbind32 (Elf32_Sym *sym, unsigned int ndx, + unsigned int *flags, const char *symname) + #endif + { +- if (*refcook != -1 && *defcook != -1) ++ if (*refcook != -1 && *defcook != -1 && symname[0] != '\0') + fprintf (stderr, "la_symbind: %s %u\n", symname, + *flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) ? 1 : 0); + return sym->st_value; +diff --git a/sysdeps/hppa/dl-lookupcfg.h b/sysdeps/hppa/dl-lookupcfg.h +index c3fea1fe5776b17a..86f6a04af46c87ba 100644 +--- a/sysdeps/hppa/dl-lookupcfg.h ++++ b/sysdeps/hppa/dl-lookupcfg.h +@@ -79,7 +79,9 @@ void attribute_hidden _dl_unmap (struct link_map *map); + /* Extract the code address from a fixup value */ + #define DL_FIXUP_VALUE_CODE_ADDR(value) ((value).ip) + #define DL_FIXUP_VALUE_ADDR(value) ((uintptr_t) &(value)) +-#define DL_FIXUP_ADDR_VALUE(addr) (*(struct fdesc *) (addr)) ++/* Clear the plabel bit to get the actual address of the descriptor. */ ++#define DL_FIXUP_ADDR_VALUE(addr) \ ++ (*(DL_FIXUP_VALUE_TYPE *) ((uintptr_t) (addr) & ~2)) + #define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr) +-#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ +- (*value) = *(struct fdesc *) (st_value) ++#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ *(value) = *(DL_FIXUP_VALUE_TYPE *) ((uintptr_t) (new_value) & ~2) diff --git a/glibc-rh2047981-38.patch b/glibc-rh2047981-38.patch new file mode 100644 index 0000000..5e7b79f --- /dev/null +++ b/glibc-rh2047981-38.patch @@ -0,0 +1,44 @@ +commit bc02f1fa2fb302eb8a486794c6b7e4811229b81e +Author: Adhemerval Zanella +Date: Fri Mar 25 08:53:42 2022 -0300 + + elf: Remove unused functions from tst-audit25(a,b) + +diff --git a/elf/tst-audit25a.c b/elf/tst-audit25a.c +index 49173e862516e876..c2cff8541b3741c3 100644 +--- a/elf/tst-audit25a.c ++++ b/elf/tst-audit25a.c +@@ -49,14 +49,6 @@ handle_restart (void) + 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[]) + { +diff --git a/elf/tst-audit25b.c b/elf/tst-audit25b.c +index a56638d501f9bff5..46391770fdfc1796 100644 +--- a/elf/tst-audit25b.c ++++ b/elf/tst-audit25b.c +@@ -48,14 +48,6 @@ handle_restart (void) + 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 && memcmp (pre, str, lenpre) == 0; +-} +- + static int + do_test (int argc, char *argv[]) + { diff --git a/glibc-rh2047981-39.patch b/glibc-rh2047981-39.patch new file mode 100644 index 0000000..36247b1 --- /dev/null +++ b/glibc-rh2047981-39.patch @@ -0,0 +1,42 @@ +commit 5325233313c66aea13e86f5dd59618e9dd74b510 +Author: Stefan Liebler +Date: Thu Apr 7 13:59:48 2022 +0200 + + S390: Fix elf/tst-audit25[ab] + + If glibc is configured with --disable-default-pie and build on + s390 with -O3, the tests elf/tst-audit25a and elf/tst-audit25b are + failing as there are additional la_symbind lines for free and malloc. + It turns out that those belong to the executable. In fact those are + the PLT-stubs. Furthermore la_symbind is also called for calloc and + realloc symbols, but those belong to libc. + + Those functions are not called at all, but dlsym'ed in + elf/dl-minimal.c: + __rtld_malloc_init_real (struct link_map *main_map) + { + ... + void *new_calloc = lookup_malloc_symbol (main_map, "calloc", &version); + void *new_free = lookup_malloc_symbol (main_map, "free", &version); + void *new_malloc = lookup_malloc_symbol (main_map, "malloc", &version); + void *new_realloc = lookup_malloc_symbol (main_map, "realloc", &version); + ... + } + + Therefore, this commit just ignored symbols with LA_SYMB_DLSYM flag. + Reviewed-by: Adheemrval Zanella + +diff --git a/elf/tst-auditmod25.c b/elf/tst-auditmod25.c +index 20640a8daf346b5f..0524c5aab17fabba 100644 +--- a/elf/tst-auditmod25.c ++++ b/elf/tst-auditmod25.c +@@ -72,7 +72,8 @@ la_symbind32 (Elf32_Sym *sym, unsigned int ndx, + unsigned int *flags, const char *symname) + #endif + { +- if (*refcook != -1 && *defcook != -1 && symname[0] != '\0') ++ if (*refcook != -1 && *defcook != -1 && symname[0] != '\0' ++ && (*flags & LA_SYMB_DLSYM) == 0) + fprintf (stderr, "la_symbind: %s %u\n", symname, + *flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) ? 1 : 0); + return sym->st_value; diff --git a/glibc-rh2047981-4.patch b/glibc-rh2047981-4.patch new file mode 100644 index 0000000..86468bd --- /dev/null +++ b/glibc-rh2047981-4.patch @@ -0,0 +1,34 @@ +commit 3ad5dab476205d6e16156cf0511fa6884b3b0fc4 +Author: Florian Weimer +Date: Tue Jul 7 09:58:45 2020 +0200 + + elf: Do not signal LA_ACT_CONSISTENT for an empty namespace [BZ #26076] + + The auditing interface identifies namespaces by their first loaded + module. Once the namespace is empty, it is no longer possible to signal + LA_ACT_CONSISTENT for it because the first loaded module is already gone + at that point. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 7fe91bdd9aaf694e..698bda929c0eab6c 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -795,8 +795,14 @@ _dl_close_worker (struct link_map *map, bool force) + if (__glibc_unlikely (do_audit)) + { + struct link_map *head = ns->_ns_loaded; +- /* Do not call the functions for any auditing object. */ +- if (head->l_auditing == 0) ++ /* 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) diff --git a/glibc-rh2047981-40.patch b/glibc-rh2047981-40.patch new file mode 100644 index 0000000..f1f4e80 --- /dev/null +++ b/glibc-rh2047981-40.patch @@ -0,0 +1,170 @@ +commit e4a2fb76efb45210c541ee3f8ef32f317783c3a8 +Author: Florian Weimer +Date: Wed May 11 20:30:49 2022 +0200 + + manual: Document the dlinfo function + + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + (cherry picked from commit 93804a1ee084d4bdc620b2b9f91615c7da0fabe1) + + Also includes partial backport of commit 5d28a8962dcb6ec056b81d730e + (the addition of manual/dynlink.texi). + +diff --git a/manual/Makefile b/manual/Makefile +index c2756640a785afe1..4c835e568f3bab67 100644 +--- a/manual/Makefile ++++ b/manual/Makefile +@@ -39,7 +39,7 @@ chapters = $(addsuffix .texi, \ + pipe socket terminal syslog math arith time \ + resource setjmp signal startup process ipc job \ + nss users sysinfo conf crypt debug threads \ +- probes tunables) ++ dynlink probes tunables) + appendices = lang.texi header.texi install.texi maint.texi platform.texi \ + contrib.texi + licenses = freemanuals.texi lgpl-2.1.texi fdl-1.3.texi +diff --git a/manual/dynlink.texi b/manual/dynlink.texi +new file mode 100644 +index 0000000000000000..dbf3de11769d8e57 +--- /dev/null ++++ b/manual/dynlink.texi +@@ -0,0 +1,100 @@ ++@node Dynamic Linker ++@c @node Dynamic Linker, Internal Probes, Threads, Top ++@c %MENU% Loading programs and shared objects. ++@chapter Dynamic Linker ++@cindex dynamic linker ++@cindex dynamic loader ++ ++The @dfn{dynamic linker} is responsible for loading dynamically linked ++programs and their dependencies (in the form of shared objects). The ++dynamic linker in @theglibc{} also supports loading shared objects (such ++as plugins) later at run time. ++ ++Dynamic linkers are sometimes called @dfn{dynamic loaders}. ++ ++@menu ++* Dynamic Linker Introspection:: Interfaces for querying mapping information. ++@end menu ++ ++@node Dynamic Linker Introspection ++@section Dynamic Linker Introspection ++ ++@Theglibc{} provides various functions for querying information from the ++dynamic linker. ++ ++@deftypefun {int} dlinfo (void *@var{handle}, int @var{request}, void *@var{arg}) ++@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} ++@standards{GNU, dlfcn.h} ++This function returns information about @var{handle} in the memory ++location @var{arg}, based on @var{request}. The @var{handle} argument ++must be a pointer returned by @code{dlopen} or @code{dlmopen}; it must ++not have been closed by @code{dlclose}. ++ ++On success, @code{dlinfo} returns 0. If there is an error, the function ++returns @math{-1}, and @code{dlerror} can be used to obtain a ++corresponding error message. ++ ++The following operations are defined for use with @var{request}: ++ ++@vtable @code ++@item RTLD_DI_LINKMAP ++The corresponding @code{struct link_map} pointer for @var{handle} is ++written to @code{*@var{arg}}. The @var{arg} argument must be the ++address of an object of type @code{struct link_map *}. ++ ++@item RTLD_DI_LMID ++The namespace identifier of @var{handle} is written to ++@code{*@var{arg}}. The @var{arg} argument must be the address of an ++object of type @code{Lmid_t}. ++ ++@item RTLD_DI_ORIGIN ++The value of the @code{$ORIGIN} dynamic string token for @var{handle} is ++written to the character array starting at @var{arg} as a ++null-terminated string. ++ ++This request type should not be used because it is prone to buffer ++overflows. ++ ++@item RTLD_DI_SERINFO ++@itemx RTLD_DI_SERINFOSIZE ++These requests can be used to obtain search path information for ++@var{handle}. For both requests, @var{arg} must point to a ++@code{Dl_serinfo} object. The @code{RTLD_DI_SERINFOSIZE} request must ++be made first; it updates the @code{dls_size} and @code{dls_cnt} members ++of the @code{Dl_serinfo} object. The caller should then allocate memory ++to store at least @code{dls_size} bytes and pass that buffer to a ++@code{RTLD_DI_SERINFO} request. This second request fills the ++@code{dls_serpath} array. The number of array elements was returned in ++the @code{dls_cnt} member in the initial @code{RTLD_DI_SERINFOSIZE} ++request. The caller is responsible for freeing the allocated buffer. ++ ++This interface is prone to buffer overflows in multi-threaded processes ++because the required size can change between the ++@code{RTLD_DI_SERINFOSIZE} and @code{RTLD_DI_SERINFO} requests. ++ ++@item RTLD_DI_TLS_DATA ++This request writes the address of the TLS block (in the current thread) ++for the shared object identified by @var{handle} to @code{*@var{arg}}. ++The argument @var{arg} must be the address of an object of type ++@code{void *}. A null pointer is written if the object does not have ++any associated TLS block. ++ ++@item RTLD_DI_TLS_MODID ++This request writes the TLS module ID for the shared object @var{handle} ++to @code{*@var{arg}}. The argument @var{arg} must be the address of an ++object of type @code{size_t}. The module ID is zero if the object ++does not have an associated TLS block. ++@end vtable ++ ++The @code{dlinfo} function is a GNU extension. ++@end deftypefun ++ ++@c FIXME these are undocumented: ++@c dladdr ++@c dladdr1 ++@c dlclose ++@c dlerror ++@c dlmopen ++@c dlopen ++@c dlsym ++@c dlvsym +diff --git a/manual/libdl.texi b/manual/libdl.texi +deleted file mode 100644 +index e3fe0452d9f41d47..0000000000000000 +--- a/manual/libdl.texi ++++ /dev/null +@@ -1,10 +0,0 @@ +-@c FIXME these are undocumented: +-@c dladdr +-@c dladdr1 +-@c dlclose +-@c dlerror +-@c dlinfo +-@c dlmopen +-@c dlopen +-@c dlsym +-@c dlvsym +diff --git a/manual/probes.texi b/manual/probes.texi +index 0ea560ed78bcfd7e..892d2451938eb379 100644 +--- a/manual/probes.texi ++++ b/manual/probes.texi +@@ -1,5 +1,5 @@ + @node Internal Probes +-@c @node Internal Probes, Tunables, Threads, Top ++@c @node Internal Probes, Tunables, Dynamic Linker, Top + @c %MENU% Probes to monitor libc internal behavior + @chapter Internal probes + +diff --git a/manual/threads.texi b/manual/threads.texi +index 87fda7d8e716e08c..1c26c57540746e3b 100644 +--- a/manual/threads.texi ++++ b/manual/threads.texi +@@ -1,5 +1,5 @@ + @node Threads +-@c @node Threads, Internal Probes, Debugging Support, Top ++@c @node Threads, Dynamic Linker, Debugging Support, Top + @c %MENU% Functions, constants, and data types for working with threads + @chapter Threads + @cindex threads diff --git a/glibc-rh2047981-41.patch b/glibc-rh2047981-41.patch new file mode 100644 index 0000000..a92e82d --- /dev/null +++ b/glibc-rh2047981-41.patch @@ -0,0 +1,268 @@ +Added $(objpfx)tst-dlinfo-phdr: $(libdl) to dlfcn/Makefile since +we still need $(libdl) in RHEL8. + +commit d056c212130280c0a54d9a4f72170ec621b70ce5 +Author: Florian Weimer +Date: Fri Apr 29 17:00:53 2022 +0200 + + dlfcn: Implement the RTLD_DI_PHDR request type for dlinfo + + The information is theoretically available via dl_iterate_phdr as + well, but that approach is very slow if there are many shared + objects. + + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + +Conflicts: + dlfcn/dlinfo.c + (missing move into libc) + +diff --git a/dlfcn/Makefile b/dlfcn/Makefile +index 0b213b7d9fefcdc9..65cee5b54d891a24 100644 +--- a/dlfcn/Makefile ++++ b/dlfcn/Makefile +@@ -59,6 +59,10 @@ tststatic3-ENV = $(tststatic-ENV) + tststatic4-ENV = $(tststatic-ENV) + tststatic5-ENV = $(tststatic-ENV) + ++tests-internal += \ ++ tst-dlinfo-phdr \ ++ # tests-internal ++ + ifneq (,$(CXX)) + modules-names += bug-atexit3-lib + else +@@ -152,3 +156,5 @@ $(objpfx)bug-dl-leaf-lib-cb.so: $(objpfx)bug-dl-leaf-lib.so + + $(objpfx)tst-rec-dlopen: $(libdl) + $(objpfx)tst-rec-dlopen.out: $(objpfx)moddummy1.so $(objpfx)moddummy2.so ++ ++$(objpfx)tst-dlinfo-phdr: $(libdl) +diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h +index 0921fd724cf7b785..61c4f59bea4eb7ac 100644 +--- a/dlfcn/dlfcn.h ++++ b/dlfcn/dlfcn.h +@@ -162,7 +162,12 @@ enum + segment, or if the calling thread has not allocated a block for it. */ + RTLD_DI_TLS_DATA = 10, + +- RTLD_DI_MAX = 10 ++ /* Treat ARG as const ElfW(Phdr) **, and store the address of the ++ program header array at that location. The dlinfo call returns ++ the number of program headers in the array. */ ++ RTLD_DI_PHDR = 11, ++ ++ RTLD_DI_MAX = 11 + }; + + +diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c +index 23ef3f57ca41afdf..50cd9af17a56f990 100644 +--- a/dlfcn/dlinfo.c ++++ b/dlfcn/dlinfo.c +@@ -38,6 +38,10 @@ struct dlinfo_args + void *handle; + int request; + void *arg; ++ ++ /* This is the value that is returned from dlinfo if no error is ++ signaled. */ ++ int result; + }; + + static void +@@ -50,6 +54,7 @@ dlinfo_doit (void *argsblock) + { + case RTLD_DI_CONFIGADDR: + default: ++ args->result = -1; + _dl_signal_error (0, NULL, NULL, N_("unsupported dlinfo request")); + break; + +@@ -85,6 +90,11 @@ dlinfo_doit (void *argsblock) + *(void **) args->arg = data; + break; + } ++ ++ case RTLD_DI_PHDR: ++ *(const ElfW(Phdr) **) args->arg = l->l_phdr; ++ args->result = l->l_phnum; ++ break; + } + } + +@@ -97,7 +107,8 @@ __dlinfo (void *handle, int request, void *arg) + # endif + + struct dlinfo_args args = { handle, request, arg }; +- return _dlerror_run (&dlinfo_doit, &args) ? -1 : 0; ++ _dlerror_run (&dlinfo_doit, &args); ++ return args.result; + } + # ifdef SHARED + strong_alias (__dlinfo, dlinfo) +diff --git a/dlfcn/tst-dlinfo-phdr.c b/dlfcn/tst-dlinfo-phdr.c +new file mode 100644 +index 0000000000000000..a15a7d48ebd3b976 +--- /dev/null ++++ b/dlfcn/tst-dlinfo-phdr.c +@@ -0,0 +1,125 @@ ++/* Test for dlinfo (RTLD_DI_PHDR). ++ 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 ++ ++/* Used to verify that the program header array appears as expected ++ among the dl_iterate_phdr callback invocations. */ ++ ++struct dlip_callback_args ++{ ++ struct link_map *l; /* l->l_addr is used to find the object. */ ++ const ElfW(Phdr) *phdr; /* Expected program header pointed. */ ++ int phnum; /* Expected program header count. */ ++ bool found; /* True if l->l_addr has been found. */ ++}; ++ ++static int ++dlip_callback (struct dl_phdr_info *dlpi, size_t size, void *closure) ++{ ++ TEST_COMPARE (sizeof (*dlpi), size); ++ struct dlip_callback_args *args = closure; ++ ++ if (dlpi->dlpi_addr == args->l->l_addr) ++ { ++ TEST_VERIFY (!args->found); ++ args->found = true; ++ TEST_VERIFY (args->phdr == dlpi->dlpi_phdr); ++ TEST_COMPARE (args->phnum, dlpi->dlpi_phnum); ++ } ++ ++ return 0; ++} ++ ++static int ++do_test (void) ++{ ++ /* Avoid a copy relocation. */ ++ struct r_debug *debug = xdlsym (RTLD_DEFAULT, "_r_debug"); ++ struct link_map *l = (struct link_map *) debug->r_map; ++ TEST_VERIFY_EXIT (l != NULL); ++ ++ do ++ { ++ printf ("info: checking link map %p (%p) for \"%s\"\n", ++ l, l->l_phdr, l->l_name); ++ ++ /* Cause dlerror () to return an error message. */ ++ dlsym (RTLD_DEFAULT, "does-not-exist"); ++ ++ /* Use the extension that link maps are valid dlopen handles. */ ++ const ElfW(Phdr) *phdr; ++ int phnum = dlinfo (l, RTLD_DI_PHDR, &phdr); ++ TEST_VERIFY (phnum >= 0); ++ /* Verify that the error message has been cleared. */ ++ TEST_COMPARE_STRING (dlerror (), NULL); ++ ++ TEST_VERIFY (phdr == l->l_phdr); ++ TEST_COMPARE (phnum, l->l_phnum); ++ ++ /* Check that we can find PT_DYNAMIC among the array. */ ++ { ++ bool dynamic_found = false; ++ for (int i = 0; i < phnum; ++i) ++ if (phdr[i].p_type == PT_DYNAMIC) ++ { ++ dynamic_found = true; ++ TEST_COMPARE ((ElfW(Addr)) l->l_ld, l->l_addr + phdr[i].p_vaddr); ++ } ++ TEST_VERIFY (dynamic_found); ++ } ++ ++ /* Check that dl_iterate_phdr finds the link map with the same ++ program headers. */ ++ { ++ struct dlip_callback_args args = ++ { ++ .l = l, ++ .phdr = phdr, ++ .phnum = phnum, ++ .found = false, ++ }; ++ TEST_COMPARE (dl_iterate_phdr (dlip_callback, &args), 0); ++ TEST_VERIFY (args.found); ++ } ++ ++ if (l->l_prev == NULL) ++ { ++ /* This is the executable, so the information is also ++ available via getauxval. */ ++ TEST_COMPARE_STRING (l->l_name, ""); ++ TEST_VERIFY (phdr == (const ElfW(Phdr) *) getauxval (AT_PHDR)); ++ TEST_COMPARE (phnum, getauxval (AT_PHNUM)); ++ } ++ ++ l = l->l_next; ++ } ++ while (l != NULL); ++ ++ return 0; ++} ++ ++#include +diff --git a/manual/dynlink.texi b/manual/dynlink.texi +index dbf3de11769d8e57..7dcac64889e389fd 100644 +--- a/manual/dynlink.texi ++++ b/manual/dynlink.texi +@@ -30,9 +30,9 @@ location @var{arg}, based on @var{request}. The @var{handle} argument + must be a pointer returned by @code{dlopen} or @code{dlmopen}; it must + not have been closed by @code{dlclose}. + +-On success, @code{dlinfo} returns 0. If there is an error, the function +-returns @math{-1}, and @code{dlerror} can be used to obtain a +-corresponding error message. ++On success, @code{dlinfo} returns 0 for most request types; exceptions ++are noted below. If there is an error, the function returns @math{-1}, ++and @code{dlerror} can be used to obtain a corresponding error message. + + The following operations are defined for use with @var{request}: + +@@ -84,6 +84,15 @@ This request writes the TLS module ID for the shared object @var{handle} + to @code{*@var{arg}}. The argument @var{arg} must be the address of an + object of type @code{size_t}. The module ID is zero if the object + does not have an associated TLS block. ++ ++@item RTLD_DI_PHDR ++This request writes the address of the program header array to ++@code{*@var{arg}}. The argument @var{arg} must be the address of an ++object of type @code{const ElfW(Phdr) *} (that is, ++@code{const Elf32_Phdr *} or @code{const Elf64_Phdr *}, as appropriate ++for the current architecture). For this request, the value returned by ++@code{dlinfo} is the number of program headers in the program header ++array. + @end vtable + + The @code{dlinfo} function is a GNU extension. diff --git a/glibc-rh2047981-42.patch b/glibc-rh2047981-42.patch new file mode 100644 index 0000000..d280e1a --- /dev/null +++ b/glibc-rh2047981-42.patch @@ -0,0 +1,296 @@ +commit ad43cac44a6860eaefcadadfb2acb349921e96bf +Author: Szabolcs Nagy +Date: Fri Jun 15 16:14:58 2018 +0100 + + rtld: Use generic argv adjustment in ld.so [BZ #23293] + + When an executable is invoked as + + ./ld.so [ld.so-args] ./exe [exe-args] + + then the argv is adujusted in ld.so before calling the entry point of + the executable so ld.so args are not visible to it. On most targets + this requires moving argv, env and auxv on the stack to ensure correct + stack alignment at the entry point. This had several issues: + + - The code for this adjustment on the stack is written in asm as part + of the target specific ld.so _start code which is hard to maintain. + + - The adjustment is done after _dl_start returns, where it's too late + to update GLRO(dl_auxv), as it is already readonly, so it points to + memory that was clobbered by the adjustment. This is bug 23293. + + - _environ is also wrong in ld.so after the adjustment, but it is + likely not used after _dl_start returns so this is not user visible. + + - _dl_argv was updated, but for this it was moved out of relro, which + changes security properties across targets unnecessarily. + + This patch introduces a generic _dl_start_args_adjust function that + handles the argument adjustments after ld.so processed its own args + and before relro protection is applied. + + The same algorithm is used on all targets, _dl_skip_args is now 0, so + existing target specific adjustment code is no longer used. The bug + affects aarch64, alpha, arc, arm, csky, ia64, nios2, s390-32 and sparc, + other targets don't need the change in principle, only for consistency. + + The GNU Hurd start code relied on _dl_skip_args after dl_main returned, + now it checks directly if args were adjusted and fixes the Hurd startup + data accordingly. + + Follow up patches can remove _dl_skip_args and DL_ARGV_NOT_RELRO. + + Tested on aarch64-linux-gnu and cross tested on i686-gnu. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/rtld.c b/elf/rtld.c +index aee5ca357f66121e..22cceeab40319582 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1127,6 +1127,62 @@ rtld_chain_load (struct link_map *main_map, char *argv0) + rtld_soname, pathname, errcode); + } + ++/* Adjusts the contents of the stack and related globals for the user ++ entry point. The ld.so processed skip_args arguments and bumped ++ _dl_argv and _dl_argc accordingly. Those arguments are removed from ++ argv here. */ ++static void ++_dl_start_args_adjust (int skip_args) ++{ ++ void **sp = (void **) (_dl_argv - skip_args - 1); ++ void **p = sp + skip_args; ++ ++ if (skip_args == 0) ++ return; ++ ++ /* Sanity check. */ ++ intptr_t argc = (intptr_t) sp[0] - skip_args; ++ assert (argc == _dl_argc); ++ ++ /* Adjust argc on stack. */ ++ sp[0] = (void *) (intptr_t) _dl_argc; ++ ++ /* Update globals in rtld. */ ++ _dl_argv -= skip_args; ++ _environ -= skip_args; ++ ++ /* Shuffle argv down. */ ++ do ++ *++sp = *++p; ++ while (*p != NULL); ++ ++ assert (_environ == (char **) (sp + 1)); ++ ++ /* Shuffle envp down. */ ++ do ++ *++sp = *++p; ++ while (*p != NULL); ++ ++#ifdef HAVE_AUX_VECTOR ++ void **auxv = (void **) GLRO(dl_auxv) - skip_args; ++ GLRO(dl_auxv) = (ElfW(auxv_t) *) auxv; /* Aliasing violation. */ ++ assert (auxv == sp + 1); ++ ++ /* Shuffle auxv down. */ ++ ElfW(auxv_t) ax; ++ char *oldp = (char *) (p + 1); ++ char *newp = (char *) (sp + 1); ++ do ++ { ++ memcpy (&ax, oldp, sizeof (ax)); ++ memcpy (newp, &ax, sizeof (ax)); ++ oldp += sizeof (ax); ++ newp += sizeof (ax); ++ } ++ while (ax.a_type != AT_NULL); ++#endif ++} ++ + static void + dl_main (const ElfW(Phdr) *phdr, + ElfW(Word) phnum, +@@ -1185,6 +1241,7 @@ dl_main (const ElfW(Phdr) *phdr, + rtld_is_main = true; + + char *argv0 = NULL; ++ char **orig_argv = _dl_argv; + + /* Note the place where the dynamic linker actually came from. */ + GL(dl_rtld_map).l_name = rtld_progname; +@@ -1199,7 +1256,6 @@ dl_main (const ElfW(Phdr) *phdr, + GLRO(dl_lazy) = -1; + } + +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + } +@@ -1208,14 +1264,12 @@ dl_main (const ElfW(Phdr) *phdr, + if (state.mode != rtld_mode_help) + state.mode = rtld_mode_verify; + +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + } + else if (! strcmp (_dl_argv[1], "--inhibit-cache")) + { + GLRO(dl_inhibit_cache) = 1; +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + } +@@ -1225,7 +1279,6 @@ dl_main (const ElfW(Phdr) *phdr, + state.library_path = _dl_argv[2]; + state.library_path_source = "--library-path"; + +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1234,7 +1287,6 @@ dl_main (const ElfW(Phdr) *phdr, + { + GLRO(dl_inhibit_rpath) = _dl_argv[2]; + +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1242,14 +1294,12 @@ dl_main (const ElfW(Phdr) *phdr, + { + audit_list_add_string (&state.audit_list, _dl_argv[2]); + +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } + else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2) + { + state.preloadarg = _dl_argv[2]; +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1257,7 +1307,6 @@ dl_main (const ElfW(Phdr) *phdr, + { + argv0 = _dl_argv[2]; + +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1265,7 +1314,6 @@ dl_main (const ElfW(Phdr) *phdr, + && _dl_argc > 2) + { + state.glibc_hwcaps_prepend = _dl_argv[2]; +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1273,7 +1321,6 @@ dl_main (const ElfW(Phdr) *phdr, + && _dl_argc > 2) + { + state.glibc_hwcaps_mask = _dl_argv[2]; +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1282,7 +1329,6 @@ dl_main (const ElfW(Phdr) *phdr, + { + state.mode = rtld_mode_list_tunables; + +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + } +@@ -1291,7 +1337,6 @@ dl_main (const ElfW(Phdr) *phdr, + { + state.mode = rtld_mode_list_diagnostics; + +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + } +@@ -1337,7 +1382,6 @@ dl_main (const ElfW(Phdr) *phdr, + _dl_usage (ld_so_name, NULL); + } + +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + +@@ -1433,6 +1477,9 @@ dl_main (const ElfW(Phdr) *phdr, + /* Set the argv[0] string now that we've processed the executable. */ + if (argv0 != NULL) + _dl_argv[0] = argv0; ++ ++ /* Adjust arguments for the application entry point. */ ++ _dl_start_args_adjust (_dl_argv - orig_argv); + } + else + { +diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c +index 7bd1d70c96c229e0..8aab46bf6396c8d4 100644 +--- a/sysdeps/mach/hurd/dl-sysdep.c ++++ b/sysdeps/mach/hurd/dl-sysdep.c +@@ -107,6 +107,7 @@ _dl_sysdep_start (void **start_argptr, + { + void go (intptr_t *argdata) + { ++ char *orig_argv0; + char **p; + + /* Cache the information in various global variables. */ +@@ -115,6 +116,8 @@ _dl_sysdep_start (void **start_argptr, + _environ = &_dl_argv[_dl_argc + 1]; + for (p = _environ; *p++;); /* Skip environ pointers and terminator. */ + ++ orig_argv0 = _dl_argv[0]; ++ + if ((void *) p == _dl_argv[0]) + { + static struct hurd_startup_data nodata; +@@ -189,30 +192,23 @@ unfmh(); /* XXX */ + + /* The call above might screw a few things up. + +- First of all, if _dl_skip_args is nonzero, we are ignoring +- the first few arguments. However, if we have no Hurd startup +- data, it is the magical convention that ARGV[0] == P. The ++ P is the location after the terminating NULL of the list of ++ environment variables. It has to point to the Hurd startup ++ data or if that's missing then P == ARGV[0] must hold. The + startup code in init-first.c will get confused if this is not + the case, so we must rearrange things to make it so. We'll +- overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args]. ++ recompute P and move the Hurd data or the new ARGV[0] there. + +- Secondly, if we need to be secure, it removes some dangerous +- environment variables. If we have no Hurd startup date this +- changes P (since that's the location after the terminating +- NULL in the list of environment variables). We do the same +- thing as in the first case but make sure we recalculate P. +- If we do have Hurd startup data, we have to move the data +- such that it starts just after the terminating NULL in the +- environment list. ++ Note: directly invoked ld.so can move arguments and env vars. + + We use memmove, since the locations might overlap. */ +- if (__libc_enable_secure || _dl_skip_args) +- { +- char **newp; + +- for (newp = _environ; *newp++;); ++ char **newp; ++ for (newp = _environ; *newp++;); + +- if (_dl_argv[-_dl_skip_args] == (char *) p) ++ if (newp != p || _dl_argv[0] != orig_argv0) ++ { ++ if (orig_argv0 == (char *) p) + { + if ((char *) newp != _dl_argv[0]) + { diff --git a/glibc-rh2047981-43.patch b/glibc-rh2047981-43.patch new file mode 100644 index 0000000..13691c9 --- /dev/null +++ b/glibc-rh2047981-43.patch @@ -0,0 +1,22 @@ +commit 62c888b3375f82a659a55ec66b1315efa2ed026a +Author: Carlos O'Donell +Date: Thu Jun 2 10:59:14 2022 -0400 + + elf: Add #include for MAX usage. + + In _dl_audit_pltenter we use MAX and so need to include param.h. + + Tested on x86_64 and i686 without regression. + +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index ec9b032eae37c103..e20b7b40e08d79e7 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + void + _dl_audit_activity_map (struct link_map *l, int action) diff --git a/glibc-rh2047981-44.patch b/glibc-rh2047981-44.patch new file mode 100644 index 0000000..e5f9389 --- /dev/null +++ b/glibc-rh2047981-44.patch @@ -0,0 +1,98 @@ +Downstream-only patch to change rtld_active () to return true during +early audit operations. GLRO (_dl_profile_output) is initialized much +earlier than GLRO (dl_init_all_dirs), before auditors run, so it is a +good replacement. + +This is addressed downstream very differently, in this commit: + +commit 8dcb6d0af07fda3607b541857e4f3970a74ed55b +Author: Florian Weimer +Date: Tue Apr 26 14:23:02 2022 +0200 + + dlfcn: Do not use rtld_active () to determine ld.so state (bug 29078) + + When audit modules are loaded, ld.so initialization is not yet + complete, and rtld_active () returns false even though ld.so is + mostly working. Instead, the static dlopen hook is used, but that + does not work at all because this is not a static dlopen situation. + + Commit 466c1ea15f461edb8e3ffaf5d86d708876343bbf ("dlfcn: Rework + static dlopen hooks") moved the hook pointer into _rtld_global_ro, + which means that separate protection is not needed anymore and the + hook pointer can be checked directly. + + The guard for disabling libio vtable hardening in _IO_vtable_check + should stay for now. + + Fixes commit 8e1472d2c1e25e6eabc2059170731365f6d5b3d1 ("ld.so: + Examine GLRO to detect inactive loader [BZ #20204]"). + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/rtld.c b/elf/rtld.c +index 22cceeab40319582..b47e84ca2fb6f03c 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2352,9 +2352,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + GLRO(dl_initial_searchlist) = *GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist; + + /* Remember the last search directory added at startup, now that +- malloc will no longer be the one from dl-minimal.c. As a side +- effect, this marks ld.so as initialized, so that the rtld_active +- function returns true from now on. */ ++ malloc will no longer be the one from dl-minimal.c. */ + GLRO(dl_init_all_dirs) = GL(dl_all_dirs); + + /* Print scope information. */ +@@ -2675,7 +2673,9 @@ process_envvars (struct dl_main_state *state) + char *envline; + char *debug_output = NULL; + +- /* This is the default place for profiling data file. */ ++ /* This is the default place for profiling data file. As a side ++ effect, this marks ld.so as initialized, so that the rtld_active ++ function returns true from now on. */ + GLRO(dl_profile_output) + = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0]; + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index d4f70211c34d1c59..9dec9e3d3b6d6aa2 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -600,18 +600,18 @@ struct rtld_global_ro + + /* Name of the shared object to be profiled (if any). */ + EXTERN const char *_dl_profile; +- /* Filename of the output file. */ ++ /* Filename of the output file. This is assigned a ++ non-NULL pointer by the ld.so startup code (after initialization ++ to NULL), so this can also serve as an indicator whether a copy ++ of ld.so is initialized and active. See the rtld_active function ++ below. */ + EXTERN const char *_dl_profile_output; + /* Name of the object we want to trace the prelinking. */ + EXTERN const char *_dl_trace_prelink; + /* Map of shared object to be prelink traced. */ + EXTERN struct link_map *_dl_trace_prelink_map; + +- /* All search directories defined at startup. This is assigned a +- non-NULL pointer by the ld.so startup code (after initialization +- to NULL), so this can also serve as an indicator whether a copy +- of ld.so is initialized and active. See the rtld_active function +- below. */ ++ /* All search directories defined at startup. */ + EXTERN struct r_search_path_elem *_dl_init_all_dirs; + + #ifdef NEED_DL_SYSINFO +@@ -1259,9 +1259,9 @@ static inline bool + rtld_active (void) + { + /* The default-initialized variable does not have a non-zero +- dl_init_all_dirs member, so this allows us to recognize an ++ dl_profile_output member, so this allows us to recognize an + initialized and active ld.so copy. */ +- return GLRO(dl_init_all_dirs) != NULL; ++ return GLRO(dl_profile_output) != NULL; + } + + static inline struct auditstate * diff --git a/glibc-rh2047981-45.patch b/glibc-rh2047981-45.patch new file mode 100644 index 0000000..0111ab9 --- /dev/null +++ b/glibc-rh2047981-45.patch @@ -0,0 +1,74 @@ +commit a64af8c9b6598f6d2685227f64f5ccb9b48c663c +Author: Florian Weimer +Date: Mon May 10 10:31:41 2021 +0200 + + scripts/versions.awk: Add strings and hashes to + + This generates new macros of this from: + + They are useful for symbol lookups using _dl_lookup_direct. + + Tested-by: Carlos O'Donell + Reviewed-by: Carlos O'Donell + +diff --git a/scripts/versions.awk b/scripts/versions.awk +index a3df316c703ea98b..0c900b83347ce8f9 100644 +--- a/scripts/versions.awk ++++ b/scripts/versions.awk +@@ -32,6 +32,29 @@ BEGIN { + sort = "sort -t. -k 1,1 -k 2n,2n -k 3 > " tmpfile; + } + ++# GNU awk does not implement the ord and chr functions. ++# ++# says that they are "written very nicely", using code similar to what ++# is included here. ++function chr(c) { ++ return sprintf("%c", c) ++} ++ ++BEGIN { ++ for (c = 1; c < 127; c++) { ++ ord_table[chr(c)] = c; ++ } ++} ++ ++function ord(c) { ++ if (ord_table[c]) { ++ return ord_table[c]; ++ } else { ++ printf("Invalid character reference: '%c'\n", c) > "/dev/stderr"; ++ ++lossage; ++ } ++} ++ + # Remove comment lines. + /^ *#/ { + next; +@@ -90,6 +113,17 @@ function close_and_move(name, real_name) { + system(move_if_change " " name " " real_name " >&2"); + } + ++# ELF hash, for use with symbol versions. ++function elf_hash(s, i, acc) { ++ acc = 0; ++ for (i = 1; i <= length(s); ++i) { ++ acc = and(lshift(acc, 4) + ord(substr(s, i, 1)), 0xffffffff); ++ top = and(acc, 0xf0000000); ++ acc = and(xor(acc, rshift(top, 24)), compl(top)); ++ } ++ return acc; ++} ++ + # Now print the accumulated information. + END { + close(sort); +@@ -145,6 +179,8 @@ END { + && oldver ~ "^GLIBC_[0-9]" \ + && sym ~ "^[A-Za-z0-9_]*$") { + ver_val = oldver; ++ printf("#define %s_STRING \"%s\"\n", first_ver_macro, ver_val) > first_ver_header; ++ printf("#define %s_HASH 0x%x\n", first_ver_macro, elf_hash(ver_val)) > first_ver_header; + gsub("\\.", "_", ver_val); + printf("#define %s %s\n", first_ver_macro, ver_val) > first_ver_header; + first_ver_seen[first_ver_macro] = 1; diff --git a/glibc-rh2047981-46.patch b/glibc-rh2047981-46.patch new file mode 100644 index 0000000..3bbd90a --- /dev/null +++ b/glibc-rh2047981-46.patch @@ -0,0 +1,227 @@ +Backport of the new test from this upstream commit: + +commit 8dcb6d0af07fda3607b541857e4f3970a74ed55b +Author: Florian Weimer +Date: Tue Apr 26 14:23:02 2022 +0200 + + dlfcn: Do not use rtld_active () to determine ld.so state (bug 29078) + + When audit modules are loaded, ld.so initialization is not yet + complete, and rtld_active () returns false even though ld.so is + mostly working. Instead, the static dlopen hook is used, but that + does not work at all because this is not a static dlopen situation. + + Commit 466c1ea15f461edb8e3ffaf5d86d708876343bbf ("dlfcn: Rework + static dlopen hooks") moved the hook pointer into _rtld_global_ro, + which means that separate protection is not needed anymore and the + hook pointer can be checked directly. + + The guard for disabling libio vtable hardening in _IO_vtable_check + should stay for now. + + Fixes commit 8e1472d2c1e25e6eabc2059170731365f6d5b3d1 ("ld.so: + Examine GLRO to detect inactive loader [BZ #20204]"). + + Reviewed-by: Adhemerval Zanella + +Conflicts: + dlfcn/dladdr.c + dlfcn/dladdr1.c + dlfcn/dlclose.c + dlfcn/dlerror.c + dlfcn/dlinfo.c + dlfcn/dlmopen.c + dlfcn/dlopen.c + dlfcn/dlopenold.c + dlfcn/dlsym.c + dlfcn/dlvsym.c + elf/dl-libc.c + (Code changes not needed.) + elf/Makefile + (Usual test list conflicts. Also added $(libdl).) + +diff --git a/elf/Makefile b/elf/Makefile +index 6d39b400060a73f3..3fae27d32676caf9 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -353,8 +353,7 @@ tests += \ + tst-audit24d \ + tst-audit25a \ + tst-audit25b \ +- tst-audit8 \ +- tst-audit9 \ ++ tst-audit26 \ + tst-auditmany \ + tst-auxobj \ + tst-auxobj-dlopen \ +@@ -659,6 +658,7 @@ modules-names = \ + tst-auditmod24c \ + tst-auditmod24d \ + tst-auditmod25 \ ++ tst-auditmod26 \ + tst-big-note-lib \ + tst-deep1mod1 \ + tst-deep1mod2 \ +@@ -2145,6 +2145,11 @@ $(objpfx)tst-audit25b: $(objpfx)tst-audit25mod1.so \ + LDFLAGS-tst-audit25b = -Wl,-z,now + tst-audit25b-ARGS = -- $(host-test-program-cmd) + ++$(objpfx)tst-audit26: $(libdl) ++$(objpfx)tst-audit26.out: $(objpfx)tst-auditmod26.so ++$(objpfx)tst-auditmod26.so: $(libsupport) $(libdl) ++tst-audit26-ENV = LD_AUDIT=$(objpfx)tst-auditmod26.so ++ + # 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/tst-audit26.c b/elf/tst-audit26.c +new file mode 100644 +index 0000000000000000..3f920e83bac247a5 +--- /dev/null ++++ b/elf/tst-audit26.c +@@ -0,0 +1,35 @@ ++/* Check the usability of functions in audit modules. ++ 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 ++ ++static int ++do_test (void) ++{ ++ /* Check that the audit module has been loaded. */ ++ void *handle = xdlopen ("mapped to libc", RTLD_LOCAL | RTLD_NOW); ++ TEST_VERIFY (handle ++ == xdlopen (LIBC_SO, RTLD_LOCAL | RTLD_NOW | RTLD_NOLOAD)); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-auditmod26.c b/elf/tst-auditmod26.c +new file mode 100644 +index 0000000000000000..db7ba95abec20f53 +--- /dev/null ++++ b/elf/tst-auditmod26.c +@@ -0,0 +1,104 @@ ++/* Check the usability of functions in audit modules. Audit module. ++ 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 ++ ++unsigned int ++la_version (unsigned int current) ++{ ++ /* Exercise various functions. */ ++ ++ /* Check dlopen, dlsym, dlclose. */ ++ void *handle = xdlopen (LIBM_SO, RTLD_LOCAL | RTLD_NOW); ++ void *ptr = xdlsym (handle, "sincos"); ++ TEST_VERIFY (ptr != NULL); ++ ptr = dlsym (handle, "SINCOS"); ++ TEST_VERIFY (ptr == NULL); ++ const char *message = dlerror (); ++ TEST_VERIFY (strstr (message, ": undefined symbol: SINCOS") != NULL); ++ ptr = dlsym (handle, "SINCOS"); ++ TEST_VERIFY (ptr == NULL); ++ xdlclose (handle); ++ TEST_COMPARE_STRING (dlerror (), NULL); ++ ++ handle = xdlopen (LIBC_SO, RTLD_LOCAL | RTLD_NOW | RTLD_NOLOAD); ++ ++ /* Check dlvsym. _exit is unlikely to gain another symbol ++ version. */ ++ TEST_VERIFY (xdlsym (handle, "_exit") ++ == xdlvsym (handle, "_exit", FIRST_VERSION_libc__exit_STRING)); ++ ++ /* Check dlinfo. */ ++ { ++ void *handle2 = NULL; ++ TEST_COMPARE (dlinfo (handle, RTLD_DI_LINKMAP, &handle2), 0); ++ TEST_VERIFY (handle2 == handle); ++ } ++ ++ /* Check dladdr and dladdr1. */ ++ Dl_info info = { }; ++ TEST_VERIFY (dladdr (&_exit, &info) != 0); ++ if (strcmp (info.dli_sname, "_Exit") != 0) /* _Exit is an alias. */ ++ TEST_COMPARE_STRING (info.dli_sname, "_exit"); ++ TEST_VERIFY (info.dli_saddr == &_exit); ++ TEST_VERIFY (strstr (info.dli_fname, LIBC_SO)); ++ void *extra_info; ++ memset (&info, 0, sizeof (info)); ++ TEST_VERIFY (dladdr1 (&_exit, &info, &extra_info, RTLD_DL_LINKMAP) != 0); ++ TEST_VERIFY (extra_info == handle); ++ ++ /* Verify that dlmopen creates a new namespace. */ ++ void *dlmopen_handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); ++ TEST_VERIFY (dlmopen_handle != handle); ++ memset (&info, 0, sizeof (info)); ++ extra_info = NULL; ++ ptr = xdlsym (dlmopen_handle, "_exit"); ++ TEST_VERIFY (dladdr1 (ptr, &info, &extra_info, RTLD_DL_LINKMAP) != 0); ++ TEST_VERIFY (extra_info == dlmopen_handle); ++ xdlclose (dlmopen_handle); ++ ++ /* Terminate the process with an error state. This does not happen ++ automatically because the audit module state is not shared with ++ the main program. */ ++ if (support_record_failure_is_failed ()) ++ { ++ fflush (stdout); ++ fflush (stderr); ++ _exit (1); ++ } ++ ++ return LAV_CURRENT; ++} ++ ++char * ++la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag) ++{ ++ if (strcmp (name, "mapped to libc") == 0) ++ return (char *) LIBC_SO; ++ else ++ return (char *) name; ++} diff --git a/glibc-rh2047981-47.patch b/glibc-rh2047981-47.patch new file mode 100644 index 0000000..c5baf0d --- /dev/null +++ b/glibc-rh2047981-47.patch @@ -0,0 +1,59 @@ +commit 2a5b4f7a715921a232f67f6810268c6cd6aa0af2 +Author: Florian Weimer +Date: Fri Jul 8 12:08:48 2022 +0200 + + elf: Rename tst-audit26 to tst-audit28 + + tst-audit26 and tst-audit27 are already used by aarch64. + + Reviewed-by: Szabolcs Nagy + +Conflicts: + elf/Makefile + (Usual test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 3fae27d32676caf9..9e721d5d4e0a1cd9 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -353,7 +353,7 @@ tests += \ + tst-audit24d \ + tst-audit25a \ + tst-audit25b \ +- tst-audit26 \ ++ tst-audit28 \ + tst-auditmany \ + tst-auxobj \ + tst-auxobj-dlopen \ +@@ -658,7 +658,7 @@ modules-names = \ + tst-auditmod24c \ + tst-auditmod24d \ + tst-auditmod25 \ +- tst-auditmod26 \ ++ tst-auditmod28 \ + tst-big-note-lib \ + tst-deep1mod1 \ + tst-deep1mod2 \ +@@ -2145,10 +2145,10 @@ $(objpfx)tst-audit25b: $(objpfx)tst-audit25mod1.so \ + LDFLAGS-tst-audit25b = -Wl,-z,now + tst-audit25b-ARGS = -- $(host-test-program-cmd) + +-$(objpfx)tst-audit26: $(libdl) +-$(objpfx)tst-audit26.out: $(objpfx)tst-auditmod26.so +-$(objpfx)tst-auditmod26.so: $(libsupport) $(libdl) +-tst-audit26-ENV = LD_AUDIT=$(objpfx)tst-auditmod26.so ++$(objpfx)tst-audit28: $(libdl) ++$(objpfx)tst-audit28.out: $(objpfx)tst-auditmod28.so ++$(objpfx)tst-auditmod28.so: $(libsupport) $(libdl) ++tst-audit28-ENV = LD_AUDIT=$(objpfx)tst-auditmod28.so + + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ +diff --git a/elf/tst-audit26.c b/elf/tst-audit28.c +similarity index 100% +rename from elf/tst-audit26.c +rename to elf/tst-audit28.c +diff --git a/elf/tst-auditmod26.c b/elf/tst-auditmod28.c +similarity index 100% +rename from elf/tst-auditmod26.c +rename to elf/tst-auditmod28.c diff --git a/glibc-rh2047981-5.patch b/glibc-rh2047981-5.patch new file mode 100644 index 0000000..43af14e --- /dev/null +++ b/glibc-rh2047981-5.patch @@ -0,0 +1,224 @@ +commit b2964eb1d9a6b8ab1250e8a881cf406182da5875 +Author: Florian Weimer +Date: Wed Apr 21 19:49:51 2021 +0200 + + dlfcn: Failures after dlmopen should not terminate process [BZ #24772] + + Commit 9e78f6f6e7134a5f299cc8de77370218f8019237 ("Implement + _dl_catch_error, _dl_signal_error in libc.so [BZ #16628]") has the + side effect that distinct namespaces, as created by dlmopen, now have + separate implementations of the rtld exception mechanism. This means + that the call to _dl_catch_error from libdl in a secondary namespace + does not actually install an exception handler because the + thread-local variable catch_hook in the libc.so copy in the secondary + namespace is distinct from that of the base namepace. As a result, a + dlsym/dlopen/... failure in a secondary namespace terminates the process + with a dynamic linker error because it looks to the exception handler + mechanism as if no handler has been installed. + + This commit restores GLRO (dl_catch_error) and uses it to set the + handler in the base namespace. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/Makefile + +diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c +index 06732460ea1512cd..e08ac3afef302817 100644 +--- a/dlfcn/dlerror.c ++++ b/dlfcn/dlerror.c +@@ -167,8 +167,10 @@ _dlerror_run (void (*operate) (void *), void *args) + result->errstring = NULL; + } + +- result->errcode = _dl_catch_error (&result->objname, &result->errstring, +- &result->malloced, operate, args); ++ result->errcode = GLRO (dl_catch_error) (&result->objname, ++ &result->errstring, ++ &result->malloced, ++ operate, args); + + /* If no error we mark that no error string is available. */ + result->returned = result->errstring == NULL; +diff --git a/elf/Makefile b/elf/Makefile +index a811919ba4568d64..e0919486a14cab1a 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -216,6 +216,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \ + tst-tls20 tst-tls21 \ + tst-rtld-run-static \ ++ tst-dlmopen-dlerror \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -349,6 +350,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + 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 \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1546,6 +1548,10 @@ $(objpfx)tst-sonamemove-dlopen.out: \ + $(objpfx)tst-sonamemove-runmod1.so \ + $(objpfx)tst-sonamemove-runmod2.so + ++$(objpfx)tst-dlmopen-dlerror: $(libdl) ++$(objpfx)tst-dlmopen-dlerror-mod.so: $(libdl) $(libsupport) ++$(objpfx)tst-dlmopen-dlerror.out: $(objpfx)tst-dlmopen-dlerror-mod.so ++ + # Override -z defs, so that we can reference an undefined symbol. + # Force lazy binding for the same reason. + LDFLAGS-tst-latepthreadmod.so = \ +diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c +index 9cb002ccfed2c7b4..7801aa433b12275f 100644 +--- a/elf/dl-error-skeleton.c ++++ b/elf/dl-error-skeleton.c +@@ -248,4 +248,16 @@ _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) + catch_hook = old_catch; + receiver = old_receiver; + } ++ ++/* Forwarder used for initializing GLRO (_dl_catch_error). */ ++int ++_rtld_catch_error (const char **objname, const char **errstring, ++ bool *mallocedp, void (*operate) (void *), ++ void *args) ++{ ++ /* The reference to _dl_catch_error will eventually be relocated to ++ point to the implementation in libc.so. */ ++ return _dl_catch_error (objname, errstring, mallocedp, operate, args); ++} ++ + #endif /* DL_ERROR_BOOTSTRAP */ +diff --git a/elf/rtld.c b/elf/rtld.c +index 461d8c114a875a9b..c445b5ca25dea193 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -365,6 +365,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro = + ._dl_lookup_symbol_x = _dl_lookup_symbol_x, + ._dl_open = _dl_open, + ._dl_close = _dl_close, ++ ._dl_catch_error = _rtld_catch_error, + ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft, + #ifdef HAVE_DL_DISCOVER_OSVERSION + ._dl_discover_osversion = _dl_discover_osversion +diff --git a/elf/tst-dlmopen-dlerror-mod.c b/elf/tst-dlmopen-dlerror-mod.c +new file mode 100644 +index 0000000000000000..7e95dcdeacf005be +--- /dev/null ++++ b/elf/tst-dlmopen-dlerror-mod.c +@@ -0,0 +1,41 @@ ++/* Check that dlfcn errors are reported properly after dlmopen. Test module. ++ 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 ++ ++/* Note: This object is not linked into the main program, so we cannot ++ use delayed test failure reporting via TEST_VERIFY etc., and have ++ to use FAIL_EXIT1 (or something else that calls exit). */ ++ ++void ++call_dlsym (void) ++{ ++ void *ptr = dlsym (NULL, "does not exist"); ++ if (ptr != NULL) ++ FAIL_EXIT1 ("dlsym did not fail as expected"); ++} ++ ++void ++call_dlopen (void) ++{ ++ void *handle = dlopen ("tst-dlmopen-dlerror does not exist", RTLD_NOW); ++ if (handle != NULL) ++ FAIL_EXIT1 ("dlopen did not fail as expected"); ++} +diff --git a/elf/tst-dlmopen-dlerror.c b/elf/tst-dlmopen-dlerror.c +new file mode 100644 +index 0000000000000000..e864d2fe4c3484ab +--- /dev/null ++++ b/elf/tst-dlmopen-dlerror.c +@@ -0,0 +1,37 @@ ++/* Check that dlfcn errors are reported properly after 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 ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-dlerror-mod.so", ++ RTLD_NOW); ++ void (*call_dlsym) (void) = xdlsym (handle, "call_dlsym"); ++ void (*call_dlopen) (void) = xdlsym (handle, "call_dlopen"); ++ ++ call_dlsym (); ++ call_dlopen (); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 7b0a667629ddc06a..d6d02aa3ccffba33 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -647,6 +647,12 @@ struct rtld_global_ro + void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen, + Lmid_t nsid, int argc, char *argv[], char *env[]); + void (*_dl_close) (void *map); ++ /* libdl in a secondary namespace (after dlopen) must use ++ _dl_catch_error from the main namespace, so it has to be ++ exported in some way. */ ++ int (*_dl_catch_error) (const char **objname, const char **errstring, ++ bool *mallocedp, void (*operate) (void *), ++ void *args); + void *(*_dl_tls_get_addr_soft) (struct link_map *); + #ifdef HAVE_DL_DISCOVER_OSVERSION + int (*_dl_discover_osversion) (void); +@@ -889,6 +895,9 @@ extern int _dl_catch_error (const char **objname, const char **errstring, + void *args); + libc_hidden_proto (_dl_catch_error) + ++/* Used for initializing GLRO (_dl_catch_error). */ ++extern __typeof__ (_dl_catch_error) _rtld_catch_error attribute_hidden; ++ + /* Call OPERATE (ARGS). If no error occurs, set *EXCEPTION to zero. + Otherwise, store a copy of the raised exception in *EXCEPTION, + which has to be freed by _dl_exception_free. As a special case, if diff --git a/glibc-rh2047981-6.patch b/glibc-rh2047981-6.patch new file mode 100644 index 0000000..09a5bf8 --- /dev/null +++ b/glibc-rh2047981-6.patch @@ -0,0 +1,822 @@ +commit fada9018199c21c469ff0e731ef75c6020074ac9 +Author: Florian Weimer +Date: Wed Apr 21 19:49:51 2021 +0200 + + dlfcn: dlerror needs to call free from the base namespace [BZ #24773] + + Calling free directly may end up freeing a pointer allocated by the + dynamic loader using malloc from libc.so in the base namespace using + the allocator from libc.so in a secondary namespace, which results in + crashes. + + This commit redirects the free call through GLRO and the dynamic + linker, to reach the correct namespace. It also cleans up the dlerror + handling along the way, so that pthread_setspecific is no longer + needed (which avoids triggering bug 24774). + +Conflicts: + dlfcn/dlfreeres.c - Remove. + malloc/set-freeres.c + Manual merge against disinct set of resources. + malloc/thread-freeres.c + Manual merge against disinct set of resources. + +diff --git a/dlfcn/Makefile b/dlfcn/Makefile +index 34f9923334f42edf..0b213b7d9fefcdc9 100644 +--- a/dlfcn/Makefile ++++ b/dlfcn/Makefile +@@ -22,9 +22,10 @@ include ../Makeconfig + headers := bits/dlfcn.h dlfcn.h + extra-libs := libdl + libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \ +- dlmopen dlfcn dlfreeres ++ dlmopen dlfcn + routines := $(patsubst %,s%,$(filter-out dlfcn,$(libdl-routines))) + elide-routines.os := $(routines) ++routines += libc_dlerror_result + + extra-libs-others := libdl + +diff --git a/dlfcn/Versions b/dlfcn/Versions +index 1df6925a92ff8b36..f07cb929aa13eaf2 100644 +--- a/dlfcn/Versions ++++ b/dlfcn/Versions +@@ -1,3 +1,8 @@ ++libc { ++ GLIBC_PRIVATE { ++ __libc_dlerror_result; ++ } ++} + libdl { + GLIBC_2.0 { + dladdr; dlclose; dlerror; dlopen; dlsym; +@@ -13,6 +18,5 @@ libdl { + } + GLIBC_PRIVATE { + _dlfcn_hook; +- __libdl_freeres; + } + } +diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c +index e08ac3afef302817..070eadbf7c1c0b1c 100644 +--- a/dlfcn/dlerror.c ++++ b/dlfcn/dlerror.c +@@ -25,6 +25,8 @@ + #include + #include + #include ++#include ++#include + + #if !defined SHARED && IS_IN (libdl) + +@@ -36,92 +38,75 @@ dlerror (void) + + #else + +-/* Type for storing results of dynamic loading actions. */ +-struct dl_action_result +- { +- int errcode; +- int returned; +- bool malloced; +- const char *objname; +- const char *errstring; +- }; +-static struct dl_action_result last_result; +-static struct dl_action_result *static_buf; +- +-/* This is the key for the thread specific memory. */ +-static __libc_key_t key; +-__libc_once_define (static, once); +- +-/* Destructor for the thread-specific data. */ +-static void init (void); +-static void free_key_mem (void *mem); +- +- + char * + __dlerror (void) + { +- char *buf = NULL; +- struct dl_action_result *result; +- + # ifdef SHARED + if (!rtld_active ()) + return _dlfcn_hook->dlerror (); + # endif + +- /* If we have not yet initialized the buffer do it now. */ +- __libc_once (once, init); ++ struct dl_action_result *result = __libc_dlerror_result; + +- /* Get error string. */ +- if (static_buf != NULL) +- result = static_buf; +- else ++ /* No libdl function has been called. No error is possible. */ ++ if (result == NULL) ++ return NULL; ++ ++ /* For an early malloc failure, clear the error flag and return the ++ error message. This marks the error as delivered. */ ++ if (result == dl_action_result_malloc_failed) + { +- /* init () has been run and we don't use the static buffer. +- So we have a valid key. */ +- result = (struct dl_action_result *) __libc_getspecific (key); +- if (result == NULL) +- result = &last_result; ++ __libc_dlerror_result = NULL; ++ return (char *) "out of memory"; + } + +- /* Test whether we already returned the string. */ +- if (result->returned != 0) ++ /* Placeholder object. This can be observed in a recursive call, ++ e.g. from an ELF constructor. */ ++ if (result->errstring == NULL) ++ return NULL; ++ ++ /* If we have already reported the error, we can free the result and ++ return NULL. See __libc_dlerror_result_free. */ ++ if (result->returned) + { +- /* We can now free the string. */ +- if (result->errstring != NULL) +- { +- if (strcmp (result->errstring, "out of memory") != 0) +- free ((char *) result->errstring); +- result->errstring = NULL; +- } ++ __libc_dlerror_result = NULL; ++ dl_action_result_errstring_free (result); ++ free (result); ++ return NULL; + } +- else if (result->errstring != NULL) +- { +- buf = (char *) result->errstring; +- int n; +- if (result->errcode == 0) +- n = __asprintf (&buf, "%s%s%s", +- result->objname, +- result->objname[0] == '\0' ? "" : ": ", +- _(result->errstring)); +- else +- n = __asprintf (&buf, "%s%s%s: %s", +- result->objname, +- result->objname[0] == '\0' ? "" : ": ", +- _(result->errstring), +- strerror (result->errcode)); +- if (n != -1) +- { +- /* We don't need the error string anymore. */ +- if (strcmp (result->errstring, "out of memory") != 0) +- free ((char *) result->errstring); +- result->errstring = buf; +- } + +- /* Mark the error as returned. */ +- result->returned = 1; +- } ++ assert (result->errstring != NULL); ++ ++ /* Create the combined error message. */ ++ char *buf; ++ int n; ++ if (result->errcode == 0) ++ n = __asprintf (&buf, "%s%s%s", ++ result->objname, ++ result->objname[0] == '\0' ? "" : ": ", ++ _(result->errstring)); ++ else ++ n = __asprintf (&buf, "%s%s%s: %s", ++ result->objname, ++ result->objname[0] == '\0' ? "" : ": ", ++ _(result->errstring), ++ strerror (result->errcode)); + +- return buf; ++ /* Mark the error as delivered. */ ++ result->returned = true; ++ ++ if (n >= 0) ++ { ++ /* Replace the error string with the newly allocated one. */ ++ dl_action_result_errstring_free (result); ++ result->errstring = buf; ++ result->errstring_source = dl_action_result_errstring_local; ++ return buf; ++ } ++ else ++ /* We could not create the combined error message, so use the ++ existing string as a fallback. */ ++ return result->errstring; + } + # ifdef SHARED + strong_alias (__dlerror, dlerror) +@@ -130,130 +115,94 @@ strong_alias (__dlerror, dlerror) + int + _dlerror_run (void (*operate) (void *), void *args) + { +- struct dl_action_result *result; +- +- /* If we have not yet initialized the buffer do it now. */ +- __libc_once (once, init); +- +- /* Get error string and number. */ +- if (static_buf != NULL) +- result = static_buf; +- else ++ struct dl_action_result *result = __libc_dlerror_result; ++ if (result != NULL) + { +- /* We don't use the static buffer and so we have a key. Use it +- to get the thread-specific buffer. */ +- result = __libc_getspecific (key); +- if (result == NULL) ++ if (result == dl_action_result_malloc_failed) + { +- result = (struct dl_action_result *) calloc (1, sizeof (*result)); +- if (result == NULL) +- /* We are out of memory. Since this is no really critical +- situation we carry on by using the global variable. +- This might lead to conflicts between the threads but +- they soon all will have memory problems. */ +- result = &last_result; +- else +- /* Set the tsd. */ +- __libc_setspecific (key, result); ++ /* Clear the previous error. */ ++ __libc_dlerror_result = NULL; ++ result = NULL; ++ } ++ else ++ { ++ /* There is an existing object. Free its error string, but ++ keep the object. */ ++ dl_action_result_errstring_free (result); ++ /* Mark the object as not containing an error. This ensures ++ that call to dlerror from, for example, an ELF ++ constructor will not notice this result object. */ ++ result->errstring = NULL; + } + } + +- if (result->errstring != NULL) +- { +- /* Free the error string from the last failed command. This can +- happen if `dlerror' was not run after an error was found. */ +- if (result->malloced) +- free ((char *) result->errstring); +- result->errstring = NULL; +- } +- +- result->errcode = GLRO (dl_catch_error) (&result->objname, +- &result->errstring, +- &result->malloced, +- operate, args); +- +- /* If no error we mark that no error string is available. */ +- result->returned = result->errstring == NULL; ++ const char *objname; ++ const char *errstring; ++ bool malloced; ++ int errcode = GLRO (dl_catch_error) (&objname, &errstring, &malloced, ++ operate, args); + +- return result->errstring != NULL; +-} ++ /* ELF constructors or destructors may have indirectly altered the ++ value of __libc_dlerror_result, therefore reload it. */ ++ result = __libc_dlerror_result; + +- +-/* Initialize buffers for results. */ +-static void +-init (void) +-{ +- if (__libc_key_create (&key, free_key_mem)) +- /* Creating the key failed. This means something really went +- wrong. In any case use a static buffer which is better than +- nothing. */ +- static_buf = &last_result; +-} +- +- +-static void +-check_free (struct dl_action_result *rec) +-{ +- if (rec->errstring != NULL +- && strcmp (rec->errstring, "out of memory") != 0) ++ if (errstring == NULL) + { +- /* We can free the string only if the allocation happened in the +- C library used by the dynamic linker. This means, it is +- always the C library in the base namespace. When we're statically +- linked, the dynamic linker is part of the program and so always +- uses the same C library we use here. */ +-#ifdef SHARED +- struct link_map *map = NULL; +- Dl_info info; +- if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0) +-#endif ++ /* There is no error. We no longer need the result object if it ++ does not contain an error. However, a recursive call may ++ have added an error even if this call did not cause it. Keep ++ the other error. */ ++ if (result != NULL && result->errstring == NULL) + { +- free ((char *) rec->errstring); +- rec->errstring = NULL; ++ __libc_dlerror_result = NULL; ++ free (result); + } ++ return 0; + } +-} +- +- +-static void +-__attribute__ ((destructor)) +-fini (void) +-{ +- check_free (&last_result); +-} +- +- +-/* Free the thread specific data, this is done if a thread terminates. */ +-static void +-free_key_mem (void *mem) +-{ +- check_free ((struct dl_action_result *) mem); ++ else ++ { ++ /* A new error occurred. Check if a result object has to be ++ allocated. */ ++ if (result == NULL || result == dl_action_result_malloc_failed) ++ { ++ /* Allocating storage for the error message after the fact ++ is not ideal. But this avoids an infinite recursion in ++ case malloc itself calls libdl functions (without ++ triggering errors). */ ++ result = malloc (sizeof (*result)); ++ if (result == NULL) ++ { ++ /* Assume that the dlfcn failure was due to a malloc ++ failure, too. */ ++ if (malloced) ++ dl_error_free ((char *) errstring); ++ __libc_dlerror_result = dl_action_result_malloc_failed; ++ return 1; ++ } ++ __libc_dlerror_result = result; ++ } ++ else ++ /* Deallocate the existing error message from a recursive ++ call, but reuse the result object. */ ++ dl_action_result_errstring_free (result); ++ ++ result->errcode = errcode; ++ result->objname = objname; ++ result->errstring = (char *) errstring; ++ result->returned = false; ++ /* In case of an error, the malloced flag indicates whether the ++ error string is constant or not. */ ++ if (malloced) ++ result->errstring_source = dl_action_result_errstring_rtld; ++ else ++ result->errstring_source = dl_action_result_errstring_constant; + +- free (mem); +- __libc_setspecific (key, NULL); ++ return 1; ++ } + } + + # ifdef SHARED + +-/* Free the dlerror-related resources. */ +-void +-__dlerror_main_freeres (void) +-{ +- /* Free the global memory if used. */ +- check_free (&last_result); +- +- if (__libc_once_get (once) && static_buf == NULL) +- { +- /* init () has been run and we don't use the static buffer. +- So we have a valid key. */ +- void *mem; +- /* Free the TSD memory if used. */ +- mem = __libc_getspecific (key); +- if (mem != NULL) +- free_key_mem (mem); +- } +-} +- + struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon)); + libdl_hidden_data_def (_dlfcn_hook) + +diff --git a/dlfcn/dlerror.h b/dlfcn/dlerror.h +new file mode 100644 +index 0000000000000000..cb9a9cea4c009452 +--- /dev/null ++++ b/dlfcn/dlerror.h +@@ -0,0 +1,92 @@ ++/* Memory management for dlerror messages. ++ 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 _DLERROR_H ++#define _DLERROR_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Source of the errstring member in struct dl_action_result, for ++ finding the right deallocation routine. */ ++enum dl_action_result_errstring_source ++ { ++ dl_action_result_errstring_constant, /* String literal, no deallocation. */ ++ dl_action_result_errstring_rtld, /* libc in the primary namespace. */ ++ dl_action_result_errstring_local, /* libc in the current namespace. */ ++ }; ++ ++struct dl_action_result ++{ ++ int errcode; ++ char errstring_source; ++ bool returned; ++ const char *objname; ++ char *errstring; ++}; ++ ++/* Used to free the errstring member of struct dl_action_result in the ++ dl_action_result_errstring_rtld case. */ ++static inline void ++dl_error_free (void *ptr) ++{ ++#ifdef SHARED ++ /* In the shared case, ld.so may use a different malloc than this ++ namespace. */ ++ GLRO (dl_error_free (ptr)); ++#else ++ /* Call the implementation directly. It still has to check for ++ pointers which cannot be freed, so do not call free directly ++ here. */ ++ _dl_error_free (ptr); ++#endif ++} ++ ++/* Deallocate RESULT->errstring, leaving *RESULT itself allocated. */ ++static inline void ++dl_action_result_errstring_free (struct dl_action_result *result) ++{ ++ switch (result->errstring_source) ++ { ++ case dl_action_result_errstring_constant: ++ break; ++ case dl_action_result_errstring_rtld: ++ dl_error_free (result->errstring); ++ break; ++ case dl_action_result_errstring_local: ++ free (result->errstring); ++ break; ++ } ++} ++ ++/* Stand-in for an error result object whose allocation failed. No ++ precise message can be reported for this, but an error must still ++ be signaled. */ ++static struct dl_action_result *const dl_action_result_malloc_failed ++ __attribute__ ((unused)) = (struct dl_action_result *) (intptr_t) -1; ++ ++/* Thread-local variable for storing dlfcn failures for subsequent ++ reporting via dlerror. */ ++extern __thread struct dl_action_result *__libc_dlerror_result ++ attribute_tls_model_ie; ++void __libc_dlerror_result_free (void) attribute_hidden; ++ ++#endif /* _DLERROR_H */ +diff --git a/dlfcn/dlfreeres.c b/dlfcn/dlfreeres.c +deleted file mode 100644 +index 4004db0edbe0c028..0000000000000000 +--- a/dlfcn/dlfreeres.c ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* Clean up allocated libdl memory on demand. +- Copyright (C) 2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-#include +-#include +-#include +- +-/* Free libdl.so resources. +- Note: Caller ensures we are called only once. */ +-void +-__libdl_freeres (void) +-{ +- call_function_static_weak (__dlerror_main_freeres); +-} +diff --git a/dlfcn/libc_dlerror_result.c b/dlfcn/libc_dlerror_result.c +new file mode 100644 +index 0000000000000000..99747186b9218680 +--- /dev/null ++++ b/dlfcn/libc_dlerror_result.c +@@ -0,0 +1,39 @@ ++/* Thread-local variable holding the dlerror result. ++ 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 ++ ++/* This pointer is either NULL, dl_action_result_malloc_failed (), or ++ has been allocated using malloc by the namespace that also contains ++ this instance of the thread-local variable. */ ++__thread struct dl_action_result *__libc_dlerror_result attribute_tls_model_ie; ++ ++/* Called during thread shutdown to free resources. */ ++void ++__libc_dlerror_result_free (void) ++{ ++ if (__libc_dlerror_result != NULL) ++ { ++ if (__libc_dlerror_result != dl_action_result_malloc_failed) ++ { ++ dl_action_result_errstring_free (__libc_dlerror_result); ++ free (__libc_dlerror_result); ++ } ++ __libc_dlerror_result = NULL; ++ } ++} +diff --git a/elf/dl-exception.c b/elf/dl-exception.c +index d24bf30a5cf39bc2..f474daf97ae76308 100644 +--- a/elf/dl-exception.c ++++ b/elf/dl-exception.c +@@ -30,6 +30,17 @@ + a pointer comparison. See below and in dlfcn/dlerror.c. */ + static const char _dl_out_of_memory[] = "out of memory"; + ++/* Call free in the main libc.so. This allows other namespaces to ++ free pointers on the main libc heap, via GLRO (dl_error_free). It ++ also avoids calling free on the special, pre-allocated ++ out-of-memory error message. */ ++void ++_dl_error_free (void *ptr) ++{ ++ if (ptr != _dl_out_of_memory) ++ free (ptr); ++} ++ + /* Dummy allocation object used if allocating the message buffer + fails. */ + static void +diff --git a/elf/rtld.c b/elf/rtld.c +index c445b5ca25dea193..e107af4014d43777 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -366,6 +366,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro = + ._dl_open = _dl_open, + ._dl_close = _dl_close, + ._dl_catch_error = _rtld_catch_error, ++ ._dl_error_free = _dl_error_free, + ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft, + #ifdef HAVE_DL_DISCOVER_OSVERSION + ._dl_discover_osversion = _dl_discover_osversion +diff --git a/elf/tst-dlmopen-dlerror-mod.c b/elf/tst-dlmopen-dlerror-mod.c +index 7e95dcdeacf005be..051025d3fa7a4d6a 100644 +--- a/elf/tst-dlmopen-dlerror-mod.c ++++ b/elf/tst-dlmopen-dlerror-mod.c +@@ -18,6 +18,8 @@ + + #include + #include ++#include ++#include + #include + + /* Note: This object is not linked into the main program, so we cannot +@@ -25,17 +27,32 @@ + to use FAIL_EXIT1 (or something else that calls exit). */ + + void +-call_dlsym (void) ++call_dlsym (const char *name) + { +- void *ptr = dlsym (NULL, "does not exist"); ++ void *ptr = dlsym (NULL, name); + if (ptr != NULL) +- FAIL_EXIT1 ("dlsym did not fail as expected"); ++ FAIL_EXIT1 ("dlsym did not fail as expected for: %s", name); ++ const char *message = dlerror (); ++ if (strstr (message, ": undefined symbol: does not exist X") == NULL) ++ FAIL_EXIT1 ("invalid dlsym error message for [[%s]]: %s", name, message); ++ message = dlerror (); ++ if (message != NULL) ++ FAIL_EXIT1 ("second dlsym for [[%s]]: %s", name, message); + } + + void +-call_dlopen (void) ++call_dlopen (const char *name) + { +- void *handle = dlopen ("tst-dlmopen-dlerror does not exist", RTLD_NOW); ++ void *handle = dlopen (name, RTLD_NOW); + if (handle != NULL) +- FAIL_EXIT1 ("dlopen did not fail as expected"); ++ FAIL_EXIT1 ("dlopen did not fail as expected for: %s", name); ++ const char *message = dlerror (); ++ if (strstr (message, "X: cannot open shared object file:" ++ " No such file or directory") == NULL ++ && strstr (message, "X: cannot open shared object file:" ++ " File name too long") == NULL) ++ FAIL_EXIT1 ("invalid dlopen error message for [[%s]]: %s", name, message); ++ message = dlerror (); ++ if (message != NULL) ++ FAIL_EXIT1 ("second dlopen for [[%s]]: %s", name, message); + } +diff --git a/elf/tst-dlmopen-dlerror.c b/elf/tst-dlmopen-dlerror.c +index e864d2fe4c3484ab..aa3d6598df119ce0 100644 +--- a/elf/tst-dlmopen-dlerror.c ++++ b/elf/tst-dlmopen-dlerror.c +@@ -17,6 +17,7 @@ + . */ + + #include ++#include + #include + #include + +@@ -25,11 +26,22 @@ do_test (void) + { + void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-dlerror-mod.so", + RTLD_NOW); +- void (*call_dlsym) (void) = xdlsym (handle, "call_dlsym"); +- void (*call_dlopen) (void) = xdlsym (handle, "call_dlopen"); +- +- call_dlsym (); +- call_dlopen (); ++ void (*call_dlsym) (const char *name) = xdlsym (handle, "call_dlsym"); ++ void (*call_dlopen) (const char *name) = xdlsym (handle, "call_dlopen"); ++ ++ /* Iterate over various name lengths. This changes the size of ++ error messages allocated by ld.so and has been shown to trigger ++ detectable heap corruption if malloc/free calls in different ++ namespaces are mixed. */ ++ char buffer[2048]; ++ char *buffer_end = &buffer[sizeof (buffer) - 2]; ++ for (char *p = stpcpy (buffer, "does not exist "); p < buffer_end; ++p) ++ { ++ p[0] = 'X'; ++ p[1] = '\0'; ++ call_dlsym (buffer); ++ call_dlopen (buffer); ++ } + + return 0; + } +diff --git a/include/dlfcn.h b/include/dlfcn.h +index 0dc57dbe2217cfe7..109586a1d968b630 100644 +--- a/include/dlfcn.h ++++ b/include/dlfcn.h +@@ -156,7 +156,5 @@ extern void __libc_register_dlfcn_hook (struct link_map *map) + attribute_hidden; + #endif + +-extern void __dlerror_main_freeres (void) attribute_hidden; +- + #endif + #endif +diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c +index cda368479f910149..43b6a2cd9da49aa9 100644 +--- a/malloc/set-freeres.c ++++ b/malloc/set-freeres.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include "../libio/libioP.h" + +@@ -26,8 +27,6 @@ DEFINE_HOOK (__libc_subfreeres, (void)); + + symbol_set_define (__libc_freeres_ptrs); + +-extern __attribute__ ((weak)) void __libdl_freeres (void); +- + extern __attribute__ ((weak)) void __libpthread_freeres (void); + + void __libc_freeres_fn_section +@@ -46,16 +45,13 @@ __libc_freeres (void) + /* We run the resource freeing after IO cleanup. */ + RUN_HOOK (__libc_subfreeres, ()); + +- /* Call the libdl list of cleanup functions +- (weak-ref-and-check). */ +- if (&__libdl_freeres != NULL) +- __libdl_freeres (); +- + /* Call the libpthread list of cleanup functions + (weak-ref-and-check). */ + if (&__libpthread_freeres != NULL) + __libpthread_freeres (); + ++ call_function_static_weak (__libc_dlerror_result_free); ++ + for (p = symbol_set_first_element (__libc_freeres_ptrs); + !symbol_set_end_p (__libc_freeres_ptrs, p); ++p) + free (*p); +diff --git a/malloc/thread-freeres.c b/malloc/thread-freeres.c +index a63b6c93f3114284..1e37a72c1f4a9c43 100644 +--- a/malloc/thread-freeres.c ++++ b/malloc/thread-freeres.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + #include + #include +@@ -32,6 +33,7 @@ __libc_thread_freeres (void) + call_function_static_weak (__rpc_thread_destroy); + call_function_static_weak (__res_thread_freeres); + call_function_static_weak (__strerror_thread_freeres); ++ call_function_static_weak (__libc_dlerror_result_free); + + /* This should come last because it shuts down malloc for this + thread and the other shutdown functions might well call free. */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index d6d02aa3ccffba33..2dd6f0c3c4aaaef5 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -653,6 +653,9 @@ struct rtld_global_ro + int (*_dl_catch_error) (const char **objname, const char **errstring, + bool *mallocedp, void (*operate) (void *), + void *args); ++ /* libdl in a secondary namespace must use free from the base ++ namespace. */ ++ void (*_dl_error_free) (void *); + void *(*_dl_tls_get_addr_soft) (struct link_map *); + #ifdef HAVE_DL_DISCOVER_OSVERSION + int (*_dl_discover_osversion) (void); +@@ -812,6 +815,10 @@ void _dl_exception_create (struct dl_exception *, const char *object, + __attribute__ ((nonnull (1, 3))); + rtld_hidden_proto (_dl_exception_create) + ++/* Used internally to implement dlerror message freeing. See ++ include/dlfcn.h and dlfcn/dlerror.c. */ ++void _dl_error_free (void *ptr) attribute_hidden; ++ + /* Like _dl_exception_create, but create errstring from a format + string FMT. Currently, only "%s" and "%%" are supported as format + directives. */ diff --git a/glibc-rh2047981-7.patch b/glibc-rh2047981-7.patch new file mode 100644 index 0000000..d1640be --- /dev/null +++ b/glibc-rh2047981-7.patch @@ -0,0 +1,134 @@ +Added $(objpfx)tst-dlmopen-gethostbyname: $(libdl) in elf/Makefile since +we still have $(libdl) in RHEL8. + +commit c2059edce20c124d1a99f1a94cc52e83b77a917a +Author: Florian Weimer +Date: Thu Jun 17 15:06:43 2021 +0200 + + elf: Use _dl_catch_error from base namespace in dl-libc.c [BZ #27646] + + dlerrror_run in elf/dl-libc.c needs to call GLRO (dl_catch_error) + from the base namespace, just like the exported dlerror + implementation. + + Fixes commit b2964eb1d9a6b8ab1250e8a881cf406182da5875 ("dlfcn: + Failures after dlmopen should not terminate process [BZ #24772]"). + + Reviewed-by: Siddhesh Poyarekar + +Conflicts: + elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index e0919486a14cab1a..30417c3ce15abcb4 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -217,6 +217,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-tls20 tst-tls21 \ + tst-rtld-run-static \ + tst-dlmopen-dlerror \ ++ tst-dlmopen-gethostbyname \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -351,6 +352,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + libmarkermod5-1 libmarkermod5-2 libmarkermod5-3 libmarkermod5-4 \ + libmarkermod5-5 tst-tls20mod-bad tst-tls21mod \ + tst-dlmopen-dlerror-mod \ ++ tst-dlmopen-gethostbyname-mod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1935,3 +1937,5 @@ $(objpfx)tst-tls21.out: $(objpfx)tst-tls21mod.so + $(objpfx)tst-tls21mod.so: $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so) + + $(objpfx)tst-rtld-run-static.out: $(objpfx)/ldconfig ++$(objpfx)tst-dlmopen-gethostbyname: $(libdl) ++$(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so +diff --git a/elf/dl-libc.c b/elf/dl-libc.c +index fc01f5514d4f656c..3a242d219756dac6 100644 +--- a/elf/dl-libc.c ++++ b/elf/dl-libc.c +@@ -43,8 +43,8 @@ dlerror_run (void (*operate) (void *), void *args) + const char *last_errstring = NULL; + bool malloced; + +- int result = (_dl_catch_error (&objname, &last_errstring, &malloced, +- operate, args) ++ int result = (GLRO (dl_catch_error) (&objname, &last_errstring, &malloced, ++ operate, args) + ?: last_errstring != NULL); + + if (result && malloced) +diff --git a/elf/tst-dlmopen-gethostbyname-mod.c b/elf/tst-dlmopen-gethostbyname-mod.c +new file mode 100644 +index 0000000000000000..9a68ea5050c3060b +--- /dev/null ++++ b/elf/tst-dlmopen-gethostbyname-mod.c +@@ -0,0 +1,29 @@ ++/* Exercise dlerror_run in elf/dl-libc.c after dlmopen, via NSS. Helper module. ++ 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 ++ ++void ++call_gethostbyname (void) ++{ ++ __nss_configure_lookup ("hosts", "files"); ++ /* This should not terminate the process due to a missing ++ _nss_files_getcanonname_r symbol. */ ++ gethostbyname ("localhost"); ++} +diff --git a/elf/tst-dlmopen-gethostbyname.c b/elf/tst-dlmopen-gethostbyname.c +new file mode 100644 +index 0000000000000000..12deb29900731c20 +--- /dev/null ++++ b/elf/tst-dlmopen-gethostbyname.c +@@ -0,0 +1,31 @@ ++/* Exercise dlerror_run in elf/dl-libc.c after dlmopen, via NSS (bug 27646). ++ 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 ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-gethostbyname-mod.so", ++ RTLD_NOW); ++ void (*call_gethostbyname) (void) = xdlsym (handle, "call_gethostbyname"); ++ call_gethostbyname (); ++ return 0; ++} ++ ++#include diff --git a/glibc-rh2047981-8.patch b/glibc-rh2047981-8.patch new file mode 100644 index 0000000..885aad4 --- /dev/null +++ b/glibc-rh2047981-8.patch @@ -0,0 +1,29 @@ +commit 832f50be6c9c010e46180d14126bbb81f35e808c +Author: Florian Weimer +Date: Tue Jul 6 13:22:01 2021 +0200 + + elf: Call free from base namespace on error in dl-libc.c [BZ #27646] + + In dlerror_run, free corresponds to the local malloc in the + namespace, but GLRO (dl_catch_error) uses the malloc from the base + namespace. elf/tst-dlmopen-gethostbyname triggers this mismatch, + but it does not crash, presumably because of a fastbin deallocation. + + Fixes commit c2059edce20c124d1a99f1a94cc52e83b77a917a ("elf: Use + _dl_catch_error from base namespace in dl-libc.c [BZ #27646]") and + commit b2964eb1d9a6b8ab1250e8a881cf406182da5875 ("dlfcn: Failures + after dlmopen should not terminate process [BZ #24772]"). + +diff --git a/elf/dl-libc.c b/elf/dl-libc.c +index 3a242d219756dac6..bb6e3378d546b234 100644 +--- a/elf/dl-libc.c ++++ b/elf/dl-libc.c +@@ -48,7 +48,7 @@ dlerror_run (void (*operate) (void *), void *args) + ?: last_errstring != NULL); + + if (result && malloced) +- free ((char *) last_errstring); ++ GLRO (dl_error_free) ((char *) last_errstring); + + return result; + } diff --git a/glibc-rh2047981-9.patch b/glibc-rh2047981-9.patch new file mode 100644 index 0000000..690027f --- /dev/null +++ b/glibc-rh2047981-9.patch @@ -0,0 +1,126 @@ +commit 3908fa933a4354309225af616d9242f595e11ccf +Author: Adhemerval Zanella +Date: Wed Jun 30 00:21:18 2021 -0300 + + elf: Fix audit regression + + Commit 03e187a41d9 added a regression when an audit module does not have + libc as DT_NEEDED (although unusual it is possible). + + Checked on x86_64-linux-gnu. + +Conflicts: + elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index 30417c3ce15abcb4..6262a4a65cfd2148 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -218,6 +218,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-rtld-run-static \ + tst-dlmopen-dlerror \ + tst-dlmopen-gethostbyname \ ++ tst-audit17 \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -1527,6 +1528,16 @@ $(objpfx)tst-auditlogmod-3.so: $(libsupport) + $(objpfx)tst-audit16.out: \ + $(objpfx)tst-auditlogmod-1.so $(objpfx)tst-auditlogmod-2.so \ + $(objpfx)tst-auditlogmod-3.so ++$(objpfx)tst-audit17.out: $(objpfx)tst-auditmod17.so ++# The test check if a audit library without libc.so on DT_NEEDED works as ++# intended, so it uses an explicit link rule. ++$(objpfx)tst-auditmod17.so: $(objpfx)tst-auditmod17.os ++ $(CC) -nostdlib -nostartfiles -shared -o $@.new \ ++ $(filter-out $(map-file),$^) ++ $(call after-link,$@.new) ++ mv -f $@.new $@ ++CFLAGS-.os += $(call elide-stack-protector,.os,tst-auditmod17) ++tst-audit17-ENV = LD_AUDIT=$(objpfx)tst-auditmod17.so + + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 736df62ce6e46d34..661a2172d1789b26 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -759,16 +759,9 @@ dl_open_worker_begin (void *a) + namespace. */ + if (!args->libc_already_loaded) + { ++ /* dlopen cannot be used to load an initial libc by design. */ + struct link_map *libc_map = GL(dl_ns)[args->nsid].libc_map; +-#ifdef SHARED +- bool initial = libc_map->l_ns == LM_ID_BASE; +-#else +- /* In the static case, there is only one namespace, but it +- contains a secondary libc (the primary libc is statically +- linked). */ +- bool initial = false; +-#endif +- _dl_call_libc_early_init (libc_map, initial); ++ _dl_call_libc_early_init (libc_map, false); + } + + #ifndef SHARED +diff --git a/elf/tst-audit17.c b/elf/tst-audit17.c +new file mode 100644 +index 0000000000000000..92986699d497845f +--- /dev/null ++++ b/elf/tst-audit17.c +@@ -0,0 +1,25 @@ ++/* Check DT_AUDIT with audit not linked against libc. ++ 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-auditmod17.c b/elf/tst-auditmod17.c +new file mode 100644 +index 0000000000000000..7a4467f597b56cf4 +--- /dev/null ++++ b/elf/tst-auditmod17.c +@@ -0,0 +1,23 @@ ++/* Check DT_AUDIT with audit not linked against libc. ++ 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 ++ . */ ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return version; ++} diff --git a/glibc-rh2054790.patch b/glibc-rh2054790.patch new file mode 100644 index 0000000..6af769e --- /dev/null +++ b/glibc-rh2054790.patch @@ -0,0 +1,27 @@ +commit ea89d5bbd9e5e514b606045d909e6ab87d851c88 +Author: Arjun Shankar +Date: Thu Feb 24 21:43:09 2022 +0100 + + localedef: Handle symbolic links when generating locale-archive + + Whenever locale data for any locale included symbolic links, localedef + would throw the error "incomplete set of locale files" and exclude it + from the generated locale archive. This commit fixes that. + + Co-authored-by: Florian Weimer + + Reviewed-by: Carlos O'Donell + +diff --git a/locale/programs/locarchive.c b/locale/programs/locarchive.c +index dec73264563bc2a0..990f7eb6830d2e57 100644 +--- a/locale/programs/locarchive.c ++++ b/locale/programs/locarchive.c +@@ -1391,7 +1391,7 @@ add_locales_to_archive (size_t nlist, char *list[], bool replace) + { + char fullname[fnamelen + 2 * strlen (d->d_name) + 7]; + +- if (d_type == DT_UNKNOWN) ++ if (d_type == DT_UNKNOWN || d_type == DT_LNK) + { + strcpy (stpcpy (stpcpy (fullname, fname), "/"), + d->d_name); diff --git a/glibc-rh2063042.patch b/glibc-rh2063042.patch new file mode 100644 index 0000000..921add1 --- /dev/null +++ b/glibc-rh2063042.patch @@ -0,0 +1,358 @@ +commit fcfc9086815bf0d277ad47a90ee3fda4c37acca8 +Author: Siddhesh Poyarekar +Date: Wed Jan 12 23:34:48 2022 +0530 + + debug: Synchronize feature guards in fortified functions [BZ #28746] + + Some functions (e.g. stpcpy, pread64, etc.) had moved to POSIX in the + main headers as they got incorporated into the standard, but their + fortified variants remained under __USE_GNU. As a result, these + functions did not get fortified when _GNU_SOURCE was not defined. + + Add test wrappers that check all functions tested in tst-chk0 at all + levels with _GNU_SOURCE undefined and then use the failures to (1) + exclude checks for _GNU_SOURCE functions in these tests and (2) Fix + feature macro guards in the fortified function headers so that they're + the same as the ones in the main headers. + + This fixes BZ #28746. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Adhemerval Zanella + +# Conflicts: +# debug/tst-fortify.c + +diff --git a/debug/Makefile b/debug/Makefile +index c92fd23dda1a7279..b0f0b7beb6d5cef5 100644 +--- a/debug/Makefile ++++ b/debug/Makefile +@@ -132,6 +132,12 @@ define cflags-lfs + CFLAGS-tst-fortify-$(1)-lfs-$(2).$(1) += -D_FILE_OFFSET_BITS=64 + endef + ++define cflags-nongnu ++CFLAGS-tst-fortify-$(1)-nongnu-$(2).$(1) += -D_LARGEFILE64_SOURCE=1 ++endef ++ ++src-chk-nongnu = \#undef _GNU_SOURCE ++ + # 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. +@@ -145,13 +151,13 @@ CFLAGS-tst-fortify-$(1)-$(2)-$(3).$(1) += -D_FORTIFY_SOURCE=$(3) -Wno-format \ + $(eval $(call cflags-$(2),$(1),$(3))) + $(objpfx)tst-fortify-$(1)-$(2)-$(3).$(1): tst-fortify.c Makefile + ( echo "/* Autogenerated from Makefile. */"; \ +- echo ""; \ ++ echo "$(src-chk-$(2))"; \ + echo "#include \"tst-fortify.c\"" ) > $$@.tmp + mv $$@.tmp $$@ + endef + + chk-extensions = c cc +-chk-types = default lfs ++chk-types = default lfs nongnu + chk-levels = 1 2 3 + + $(foreach e,$(chk-extensions), \ +diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c +index 5e76081255316a93..1668294e48b5c63c 100644 +--- a/debug/tst-fortify.c ++++ b/debug/tst-fortify.c +@@ -1,4 +1,5 @@ +-/* Copyright (C) 2004-2018 Free Software Foundation, Inc. ++/* Copyright (C) 2004-2022 Free Software Foundation, Inc. ++ Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2004. + +@@ -37,6 +38,17 @@ + #include + #include + ++#ifndef _GNU_SOURCE ++# define MEMPCPY memcpy ++# define WMEMPCPY wmemcpy ++# define MEMPCPY_RET(x) 0 ++# define WMEMPCPY_RET(x) 0 ++#else ++# define MEMPCPY mempcpy ++# define WMEMPCPY wmempcpy ++# define MEMPCPY_RET(x) __builtin_strlen (x) ++# define WMEMPCPY_RET(x) wcslen (x) ++#endif + + #define obstack_chunk_alloc malloc + #define obstack_chunk_free free +@@ -163,7 +175,7 @@ do_test (void) + if (memcmp (buf, "aabcdefghi", 10)) + FAIL (); + +- if (mempcpy (buf + 5, "abcde", 5) != buf + 10 ++ if (MEMPCPY (buf + 5, "abcde", 5) != buf + 5 + MEMPCPY_RET ("abcde") + || memcmp (buf, "aabcdabcde", 10)) + FAIL (); + +@@ -208,7 +220,7 @@ do_test (void) + if (memcmp (buf, "aabcdefghi", 10)) + FAIL (); + +- if (mempcpy (buf + 5, "abcde", l0 + 5) != buf + 10 ++ if (MEMPCPY (buf + 5, "abcde", l0 + 5) != buf + 5 + MEMPCPY_RET ("abcde") + || memcmp (buf, "aabcdabcde", 10)) + FAIL (); + +@@ -267,7 +279,8 @@ do_test (void) + if (memcmp (a.buf1, "aabcdefghi", 10)) + FAIL (); + +- if (mempcpy (a.buf1 + 5, "abcde", l0 + 5) != a.buf1 + 10 ++ if (MEMPCPY (a.buf1 + 5, "abcde", l0 + 5) ++ != a.buf1 + 5 + MEMPCPY_RET ("abcde") + || memcmp (a.buf1, "aabcdabcde", 10)) + FAIL (); + +@@ -348,6 +361,7 @@ do_test (void) + bcopy (buf + 1, buf + 2, l0 + 9); + CHK_FAIL_END + ++#ifdef _GNU_SOURCE + CHK_FAIL_START + p = (char *) mempcpy (buf + 6, "abcde", 5); + CHK_FAIL_END +@@ -355,6 +369,7 @@ do_test (void) + CHK_FAIL_START + p = (char *) mempcpy (buf + 6, "abcde", l0 + 5); + CHK_FAIL_END ++#endif + + CHK_FAIL_START + memset (buf + 9, 'j', 2); +@@ -465,6 +480,7 @@ do_test (void) + bcopy (a.buf1 + 1, a.buf1 + 2, l0 + 9); + CHK_FAIL_END + ++#ifdef _GNU_SOURCE + CHK_FAIL_START + p = (char *) mempcpy (a.buf1 + 6, "abcde", 5); + CHK_FAIL_END +@@ -472,6 +488,7 @@ do_test (void) + CHK_FAIL_START + p = (char *) mempcpy (a.buf1 + 6, "abcde", l0 + 5); + CHK_FAIL_END ++#endif + + CHK_FAIL_START + memset (a.buf1 + 9, 'j', 2); +@@ -551,7 +568,7 @@ do_test (void) + if (wmemcmp (wbuf, L"aabcdefghi", 10)) + FAIL (); + +- if (wmempcpy (wbuf + 5, L"abcde", 5) != wbuf + 10 ++ if (WMEMPCPY (wbuf + 5, L"abcde", 5) != wbuf + 5 + WMEMPCPY_RET (L"abcde") + || wmemcmp (wbuf, L"aabcdabcde", 10)) + FAIL (); + +@@ -584,7 +601,8 @@ do_test (void) + if (wmemcmp (wbuf, L"aabcdefghi", 10)) + FAIL (); + +- if (wmempcpy (wbuf + 5, L"abcde", l0 + 5) != wbuf + 10 ++ if (WMEMPCPY (wbuf + 5, L"abcde", l0 + 5) ++ != wbuf + 5 + WMEMPCPY_RET (L"abcde") + || wmemcmp (wbuf, L"aabcdabcde", 10)) + FAIL (); + +@@ -626,7 +644,8 @@ do_test (void) + if (wmemcmp (wa.buf1, L"aabcdefghi", 10)) + FAIL (); + +- if (wmempcpy (wa.buf1 + 5, L"abcde", l0 + 5) != wa.buf1 + 10 ++ if (WMEMPCPY (wa.buf1 + 5, L"abcde", l0 + 5) ++ != wa.buf1 + 5 + WMEMPCPY_RET (L"abcde") + || wmemcmp (wa.buf1, L"aabcdabcde", 10)) + FAIL (); + +@@ -695,6 +714,7 @@ do_test (void) + wmemmove (wbuf + 2, wbuf + 1, l0 + 9); + CHK_FAIL_END + ++#ifdef _GNU_SOURCE + CHK_FAIL_START + wp = wmempcpy (wbuf + 6, L"abcde", 5); + CHK_FAIL_END +@@ -702,6 +722,7 @@ do_test (void) + CHK_FAIL_START + wp = wmempcpy (wbuf + 6, L"abcde", l0 + 5); + CHK_FAIL_END ++#endif + + CHK_FAIL_START + wmemset (wbuf + 9, L'j', 2); +@@ -769,6 +790,7 @@ do_test (void) + wmemmove (wa.buf1 + 2, wa.buf1 + 1, l0 + 9); + CHK_FAIL_END + ++#ifdef _GNU_SOURCE + CHK_FAIL_START + wp = wmempcpy (wa.buf1 + 6, L"abcde", 5); + CHK_FAIL_END +@@ -776,6 +798,7 @@ do_test (void) + CHK_FAIL_START + wp = wmempcpy (wa.buf1 + 6, L"abcde", l0 + 5); + CHK_FAIL_END ++#endif + + CHK_FAIL_START + wmemset (wa.buf1 + 9, L'j', 2); +@@ -907,6 +930,7 @@ do_test (void) + if (fprintf (fp, buf2 + 4, str5) != 7) + FAIL (); + ++#ifdef _GNU_SOURCE + char *my_ptr = NULL; + strcpy (buf2 + 2, "%n%s%n"); + /* When the format string is writable and contains %n, +@@ -936,6 +960,7 @@ do_test (void) + if (obstack_printf (&obs, "%s%n%s%n", str4, &n1, str5, &n1) != 14) + FAIL (); + obstack_free (&obs, NULL); ++#endif + + if (freopen (temp_filename, "r", stdin) == NULL) + { +@@ -983,6 +1008,7 @@ do_test (void) + + rewind (stdin); + ++#ifdef _GNU_SOURCE + if (fgets_unlocked (buf, buf_size, stdin) != buf + || memcmp (buf, "abcdefgh\n", 10)) + FAIL (); +@@ -1009,6 +1035,7 @@ do_test (void) + #endif + + rewind (stdin); ++#endif + + if (fread (buf, 1, buf_size, stdin) != buf_size + || memcmp (buf, "abcdefgh\nA", 10)) +@@ -1579,7 +1606,10 @@ do_test (void) + ret = 1; + } + +- int fd = posix_openpt (O_RDWR); ++ int fd; ++ ++#ifdef _GNU_SOURCE ++ fd = posix_openpt (O_RDWR); + if (fd != -1) + { + char enough[1000]; +@@ -1595,6 +1625,7 @@ do_test (void) + #endif + close (fd); + } ++#endif + + #if PATH_MAX > 0 + confstr (_CS_GNU_LIBC_VERSION, largebuf, sizeof (largebuf)); +@@ -1712,8 +1743,9 @@ do_test (void) + poll (fds, l0 + 2, 0); + CHK_FAIL_END + #endif ++#ifdef _GNU_SOURCE + ppoll (fds, 1, NULL, NULL); +-#if __USE_FORTIFY_LEVEL >= 1 ++# if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START + ppoll (fds, 2, NULL, NULL); + CHK_FAIL_END +@@ -1721,6 +1753,7 @@ do_test (void) + CHK_FAIL_START + ppoll (fds, l0 + 2, NULL, NULL); + CHK_FAIL_END ++# endif + #endif + + return ret; +diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h +index a456d1723547db70..ddfaed4dd7574cd2 100644 +--- a/posix/bits/unistd.h ++++ b/posix/bits/unistd.h +@@ -38,7 +38,7 @@ read (int __fd, void *__buf, size_t __nbytes) + __fd, __buf, __nbytes); + } + +-#ifdef __USE_UNIX98 ++#if defined __USE_UNIX98 || defined __USE_XOPEN2K8 + extern ssize_t __pread_chk (int __fd, void *__buf, size_t __nbytes, + __off_t __offset, size_t __bufsize) __wur; + extern ssize_t __pread64_chk (int __fd, void *__buf, size_t __nbytes, +diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h +index 27ec273ec41cd81c..3f86629bf8fc51a2 100644 +--- a/string/bits/string_fortified.h ++++ b/string/bits/string_fortified.h +@@ -94,7 +94,7 @@ __NTH (strcpy (char *__restrict __dest, const char *__restrict __src)) + return __builtin___strcpy_chk (__dest, __src, __glibc_objsize (__dest)); + } + +-#ifdef __USE_GNU ++#ifdef __USE_XOPEN2K8 + __fortify_function char * + __NTH (stpcpy (char *__restrict __dest, const char *__restrict __src)) + { +@@ -111,14 +111,15 @@ __NTH (strncpy (char *__restrict __dest, const char *__restrict __src, + __glibc_objsize (__dest)); + } + +-#if __GNUC_PREREQ (4, 7) || __glibc_clang_prereq (2, 6) ++#ifdef __USE_XOPEN2K8 ++# 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, + __glibc_objsize (__dest)); + } +-#else ++# 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, +@@ -132,6 +133,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 + #endif + + +diff --git a/support/xsignal.h b/support/xsignal.h +index 9ab8d1bfddf6c598..fae6108a522ae5fe 100644 +--- a/support/xsignal.h ++++ b/support/xsignal.h +@@ -28,7 +28,9 @@ __BEGIN_DECLS + terminate the process on error. */ + + void xraise (int sig); ++#ifdef _GNU_SOURCE + sighandler_t xsignal (int sig, sighandler_t handler); ++#endif + void xsigaction (int sig, const struct sigaction *newact, + struct sigaction *oldact); + +diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h +index f82bba481981e4fb..5c68979e96a504b4 100644 +--- a/wcsmbs/bits/wchar2.h ++++ b/wcsmbs/bits/wchar2.h +@@ -457,7 +457,7 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src, + } + + +-#ifdef __USE_GNU ++#ifdef __USE_XOPEN2K8 + extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, + const char **__restrict __src, size_t __nmc, + size_t __len, mbstate_t *__restrict __ps, diff --git a/glibc-rh2061727.patch b/glibc-rh2063712.patch similarity index 100% rename from glibc-rh2061727.patch rename to glibc-rh2063712.patch diff --git a/glibc-rh2073432.patch b/glibc-rh2071745.patch similarity index 100% rename from glibc-rh2073432.patch rename to glibc-rh2071745.patch diff --git a/glibc-rh2072329.patch b/glibc-rh2072329.patch new file mode 100644 index 0000000..e26331e --- /dev/null +++ b/glibc-rh2072329.patch @@ -0,0 +1,86 @@ +commit 33e03f9cd2be4f2cd62f93fda539cc07d9c8130e +Author: Joan Bruguera +Date: Mon Apr 11 19:49:56 2022 +0200 + + misc: Fix rare fortify crash on wchar funcs. [BZ 29030] + + If `__glibc_objsize (__o) == (size_t) -1` (i.e. `__o` is unknown size), fortify + checks should pass, and `__whatever_alias` should be called. + + Previously, `__glibc_objsize (__o) == (size_t) -1` was explicitly checked, but + on commit a643f60c53876b, this was moved into `__glibc_safe_or_unknown_len`. + + A comment says the -1 case should work as: "The -1 check is redundant because + since it implies that __glibc_safe_len_cond is true.". But this fails when: + * `__s > 1` + * `__osz == -1` (i.e. unknown size at compile time) + * `__l` is big enough + * `__l * __s <= __osz` can be folded to a constant + (I only found this to be true for `mbsrtowcs` and other functions in wchar2.h) + + In this case `__l * __s <= __osz` is false, and `__whatever_chk_warn` will be + called by `__glibc_fortify` or `__glibc_fortify_n` and crash the program. + + This commit adds the explicit `__osz == -1` check again. + moc crashes on startup due to this, see: https://bugs.archlinux.org/task/74041 + + Minimal test case (test.c): + #include + + int main (void) + { + const char *hw = "HelloWorld"; + mbsrtowcs (NULL, &hw, (size_t)-1, NULL); + return 0; + } + + Build with: + gcc -O2 -Wp,-D_FORTIFY_SOURCE=2 test.c -o test && ./test + + Output: + *** buffer overflow detected ***: terminated + + Fixes: BZ #29030 + Signed-off-by: Joan Bruguera + Signed-off-by: Siddhesh Poyarekar + +diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c +index 1668294e48b5c63c..701bffd1d664f289 100644 +--- a/debug/tst-fortify.c ++++ b/debug/tst-fortify.c +@@ -1505,6 +1505,11 @@ do_test (void) + CHK_FAIL_END + #endif + ++ /* Bug 29030 regresion check */ ++ cp = "HelloWorld"; ++ if (mbsrtowcs (NULL, &cp, (size_t)-1, &s) != 10) ++ FAIL (); ++ + cp = "A"; + if (mbstowcs (wenough, cp, 10) != 1 + || wcscmp (wenough, L"A") != 0) +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index a17ae0ed87e6163f..404496c7d6da4fb3 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -143,13 +143,13 @@ + || (__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. */ ++ condition can be folded to a constant and if it is true, or unknown (-1) */ + #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)) ++ ((__osz) == (__SIZE_TYPE__) -1 \ ++ || (__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 unsafe if the + __L * __S <= __OBJSZ condition can be folded to a constant and if it is diff --git a/glibc-rh2077835.patch b/glibc-rh2077835.patch new file mode 100644 index 0000000..7323d49 --- /dev/null +++ b/glibc-rh2077835.patch @@ -0,0 +1,211 @@ +commit 2376944b9e5c0364b9fb473e4d8dabca31b57167 +Author: Stefan Liebler +Date: Wed Apr 13 14:36:09 2022 +0200 + + S390: Add new s390 platform z16. + + The new IBM z16 is added to platform string array. + The macro _DL_PLATFORMS_COUNT is incremented. + + _dl_hwcaps_subdir is extended by "z16" if HWCAP_S390_VXRS_PDE2 + is set. HWCAP_S390_NNPA is not tested in _dl_hwcaps_subdirs_active + as those instructions may be replaced or removed in future. + + tst-glibc-hwcaps.c is extended in order to test z16 via new marker5. + + A fatal glibc error is dumped if glibc was build with architecture + level set for z16, but run on an older machine. (See dl-hwcap-check.h) + +Reworked for RHEL 8.7.0 + +diff -Nrup a/elf/Makefile b/elf/Makefile +--- a/elf/Makefile 2022-05-16 21:48:11.267916411 -0400 ++++ b/elf/Makefile 2022-05-16 21:48:56.106095151 -0400 +@@ -347,7 +347,8 @@ modules-names = testobj1 testobj2 testob + libmarkermod2-1 libmarkermod2-2 \ + libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \ + libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ +- tst-tls20mod-bad tst-tls21mod \ ++ libmarkermod5-1 libmarkermod5-2 libmarkermod5-3 libmarkermod5-4 \ ++ libmarkermod5-5 tst-tls20mod-bad tst-tls21mod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1782,6 +1783,7 @@ LDFLAGS-libmarkermod1-1.so += -Wl,-sonam + LDFLAGS-libmarkermod2-1.so += -Wl,-soname,libmarkermod2.so + LDFLAGS-libmarkermod3-1.so += -Wl,-soname,libmarkermod3.so + LDFLAGS-libmarkermod4-1.so += -Wl,-soname,libmarkermod4.so ++LDFLAGS-libmarkermod5-1.so += -Wl,-soname,libmarkermod5.so + $(objpfx)libmarkermod%.os : markermodMARKER-VALUE.c + $(compile-command.c) \ + -DMARKER=marker$(firstword $(subst -, ,$*)) \ +@@ -1794,6 +1796,8 @@ $(objpfx)libmarkermod3.so: $(objpfx)libm + cp $< $@ + $(objpfx)libmarkermod4.so: $(objpfx)libmarkermod4-1.so + cp $< $@ ++$(objpfx)libmarkermod5.so: $(objpfx)libmarkermod5-1.so ++ cp $< $@ + + # tst-glibc-hwcaps-prepend checks that --glibc-hwcaps-prepend is + # preferred over auto-detected subdirectories. +diff -Nrup a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +--- a/elf/tst-glibc-hwcaps-cache.script 2022-05-16 21:48:11.053915558 -0400 ++++ b/elf/tst-glibc-hwcaps-cache.script 2022-05-16 21:48:56.107095155 -0400 +@@ -4,6 +4,7 @@ + cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so + cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so + cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so ++cp $B/elf/libmarkermod5-1.so $L/libmarkermod5.so + + mkdirp 0770 $L/glibc-hwcaps/power9 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/power9/libmarkermod2.so +@@ -20,6 +21,11 @@ mkdirp 0770 $L/glibc-hwcaps/z15 + cp $B/elf/libmarkermod4-2.so $L/glibc-hwcaps/z13/libmarkermod4.so + cp $B/elf/libmarkermod4-3.so $L/glibc-hwcaps/z14/libmarkermod4.so + cp $B/elf/libmarkermod4-4.so $L/glibc-hwcaps/z15/libmarkermod4.so ++mkdirp 0770 $L/glibc-hwcaps/z16 ++cp $B/elf/libmarkermod5-2.so $L/glibc-hwcaps/z13/libmarkermod5.so ++cp $B/elf/libmarkermod5-3.so $L/glibc-hwcaps/z14/libmarkermod5.so ++cp $B/elf/libmarkermod5-4.so $L/glibc-hwcaps/z15/libmarkermod5.so ++cp $B/elf/libmarkermod5-5.so $L/glibc-hwcaps/z16/libmarkermod5.so + + mkdirp 0770 $L/glibc-hwcaps/x86-64-v2 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so +diff -Nrup a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +--- a/sysdeps/s390/dl-procinfo.c 2022-05-16 21:48:11.250916343 -0400 ++++ b/sysdeps/s390/dl-procinfo.c 2022-05-16 21:48:56.107095155 -0400 +@@ -64,11 +64,12 @@ PROCINFO_CLASS const char _dl_s390_cap_f + #if !defined PROCINFO_DECL && defined SHARED + ._dl_s390_platforms + #else +-PROCINFO_CLASS const char _dl_s390_platforms[10][7] ++PROCINFO_CLASS const char _dl_s390_platforms[11][7] + #endif + #ifndef PROCINFO_DECL + = { +- "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15" ++ "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15", ++ "z16" + } + #endif + #if !defined SHARED || defined PROCINFO_DECL +diff -Nrup a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +--- a/sysdeps/s390/dl-procinfo.h 2022-05-16 21:48:11.250916343 -0400 ++++ b/sysdeps/s390/dl-procinfo.h 2022-05-16 21:48:56.107095155 -0400 +@@ -23,7 +23,7 @@ + + #define _DL_HWCAP_COUNT 23 + +-#define _DL_PLATFORMS_COUNT 10 ++#define _DL_PLATFORMS_COUNT 11 + + /* The kernel provides up to 32 capability bits with elf_hwcap. */ + #define _DL_FIRST_PLATFORM 32 +diff -Nrup a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c +--- a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c 2022-05-16 21:48:11.053915558 -0400 ++++ b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c 2022-05-16 21:58:02.840301911 -0400 +@@ -19,8 +19,8 @@ + #include + #include + +-const char _dl_hwcaps_subdirs[] = "z15:z14:z13"; +-enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs. */ ++const char _dl_hwcaps_subdirs[] = "z16:z15:z14:z13"; ++enum { subdirs_count = 4 }; /* Number of components in _dl_hwcaps_subdirs. */ + + uint32_t + _dl_hwcaps_subdirs_active (void) +@@ -50,5 +50,12 @@ _dl_hwcaps_subdirs_active (void) + return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); + ++active; + ++ /* z16. ++ Note: We do not list HWCAP_S390_NNPA here as, according to the Principles of ++ Operation, those instructions may be replaced or removed in future. */ ++ if (!(GLRO (dl_hwcap) & HWCAP_S390_VXRS_PDE2)) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ + return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); + } +diff -Nrup a/sysdeps/s390/s390-64/Makefile b/sysdeps/s390/s390-64/Makefile +--- a/sysdeps/s390/s390-64/Makefile 2022-05-16 21:48:11.053915558 -0400 ++++ b/sysdeps/s390/s390-64/Makefile 2022-05-16 21:54:08.832355745 -0400 +@@ -7,8 +7,11 @@ CFLAGS-rtld.c += -Wno-uninitialized -Wno + CFLAGS-dl-load.c += -Wno-unused + CFLAGS-dl-reloc.c += -Wno-unused + +-$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so \ +- $(objpfx)libmarkermod3-1.so $(objpfx)libmarkermod4-1.so ++$(objpfx)tst-glibc-hwcaps: \ ++ $(objpfx)libmarkermod2-1.so \ ++ $(objpfx)libmarkermod3-1.so \ ++ $(objpfx)libmarkermod4-1.so \ ++ $(objpfx)libmarkermod5-1.so + $(objpfx)tst-glibc-hwcaps.out: \ + $(objpfx)libmarkermod2.so \ + $(objpfx)glibc-hwcaps/z13/libmarkermod2.so \ +@@ -19,6 +22,11 @@ $(objpfx)tst-glibc-hwcaps.out: \ + $(objpfx)glibc-hwcaps/z13/libmarkermod4.so \ + $(objpfx)glibc-hwcaps/z14/libmarkermod4.so \ + $(objpfx)glibc-hwcaps/z15/libmarkermod4.so \ ++ $(objpfx)libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z13/libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z14/libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z15/libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z16/libmarkermod5.so + + $(objpfx)glibc-hwcaps/z13/libmarkermod2.so: $(objpfx)libmarkermod2-2.so + $(make-target-directory) +@@ -38,6 +46,18 @@ $(objpfx)glibc-hwcaps/z14/libmarkermod4. + $(objpfx)glibc-hwcaps/z15/libmarkermod4.so: $(objpfx)libmarkermod4-4.so + $(make-target-directory) + cp $< $@ ++$(objpfx)glibc-hwcaps/z13/libmarkermod5.so: $(objpfx)libmarkermod5-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z14/libmarkermod5.so: $(objpfx)libmarkermod5-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z15/libmarkermod5.so: $(objpfx)libmarkermod5-4.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z16/libmarkermod5.so: $(objpfx)libmarkermod5-5.so ++ $(make-target-directory) ++ cp $< $@ + + ifeq (no,$(build-hardcoded-path-in-tests)) + # This is an ld.so.cache test, and RPATH/RUNPATH in the executable +diff -Nrup a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c +--- a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c 2022-05-16 21:48:11.053915558 -0400 ++++ b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c 2022-05-16 21:48:56.107095155 -0400 +@@ -25,6 +25,7 @@ + extern int marker2 (void); + extern int marker3 (void); + extern int marker4 (void); ++extern int marker5 (void); + + /* Return the arch level, 10 for the baseline libmarkermod*.so's. */ + static int +@@ -63,9 +64,13 @@ compute_level (void) + return 12; + if (strcmp (platform, "z15") == 0) + return 13; ++ if (strcmp (platform, "z16") == 0) ++ return 14; + printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform); + /* Assume that the new platform supports z15. */ + return 13; ++ /* Assume that the new platform supports z16. */ ++ return 14; + } + + static int +@@ -76,6 +81,7 @@ do_test (void) + TEST_COMPARE (marker2 (), MIN (level - 9, 2)); + TEST_COMPARE (marker3 (), MIN (level - 9, 3)); + TEST_COMPARE (marker4 (), MIN (level - 9, 4)); ++ TEST_COMPARE (marker5 (), MIN (level - 9, 5)); + return 0; + } + diff --git a/glibc-rh2080349-1.patch b/glibc-rh2080349-1.patch new file mode 100644 index 0000000..0bc7524 --- /dev/null +++ b/glibc-rh2080349-1.patch @@ -0,0 +1,37 @@ +commit 4a7c342605bc653f72d60c36abe698986fb5cb47 +Author: Joseph Myers +Date: Wed Apr 28 17:19:24 2021 +0000 + + Update syscall lists for Linux 5.12. + + Linux 5.12 has one new syscall, mount_setattr. Update + syscall-names.list and regenerate the arch-syscall.h headers with + build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.12. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index f6cb34089d..8e3cfa0e77 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.11. +-kernel 5.11 ++# The list of system calls is current as of Linux 5.12. ++kernel 5.12 + + FAST_atomic_update + FAST_cmpxchg +@@ -258,6 +258,7 @@ mmap + mmap2 + modify_ldt + mount ++mount_setattr + move_mount + move_pages + mprotect diff --git a/glibc-rh2080349-2.patch b/glibc-rh2080349-2.patch new file mode 100644 index 0000000..6084110 --- /dev/null +++ b/glibc-rh2080349-2.patch @@ -0,0 +1,40 @@ +commit b1b4f7209ecaad4bf9a5d0d2ef1338409d364bac +Author: Joseph Myers +Date: Thu Jul 1 17:37:36 2021 +0000 + + Update syscall lists for Linux 5.13 + + Linux 5.13 has three new syscalls (landlock_create_ruleset, + landlock_add_rule, landlock_restrict_self). Update syscall-names.list + and regenerate the arch-syscall.h headers with build-many-glibcs.py + update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.13. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 8e3cfa0e77..89c5895b9b 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.12. +-kernel 5.12 ++# The list of system calls is current as of Linux 5.13. ++kernel 5.13 + + FAST_atomic_update + FAST_cmpxchg +@@ -224,6 +224,9 @@ kexec_file_load + kexec_load + keyctl + kill ++landlock_add_rule ++landlock_create_ruleset ++landlock_restrict_self + lchown + lchown32 + lgetxattr diff --git a/glibc-rh2080349-3.patch b/glibc-rh2080349-3.patch new file mode 100644 index 0000000..7293e03 --- /dev/null +++ b/glibc-rh2080349-3.patch @@ -0,0 +1,45 @@ +commit 89dc0372a9055e7ef86fe19be6201fa0b16b2f0e +Author: Joseph Myers +Date: Wed Sep 8 12:42:06 2021 +0000 + + Update syscall lists for Linux 5.14 + + Linux 5.14 has two new syscalls, memfd_secret (on some architectures + only) and quotactl_fd. Update syscall-names.list and regenerate the + arch-syscall.h headers with build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.14. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 89c5895b9b..fd98893b0e 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.13. +-kernel 5.13 ++# The list of system calls is current as of Linux 5.14. ++kernel 5.14 + + FAST_atomic_update + FAST_cmpxchg +@@ -247,6 +247,7 @@ madvise + mbind + membarrier + memfd_create ++memfd_secret + memory_ordering + migrate_pages + mincore +@@ -452,6 +453,7 @@ pwritev + pwritev2 + query_module + quotactl ++quotactl_fd + read + readahead + readdir diff --git a/glibc-rh2080349-4.patch b/glibc-rh2080349-4.patch new file mode 100644 index 0000000..205b903 --- /dev/null +++ b/glibc-rh2080349-4.patch @@ -0,0 +1,43 @@ +commit 3387c40a8bbad5faf85b1feb56429cb20feaa640 +Author: Joseph Myers +Date: Wed Nov 10 15:21:19 2021 +0000 + + Update syscall lists for Linux 5.15 + + Linux 5.15 has one new syscall, process_mrelease (and also enables the + clone3 syscall for RV32). It also has a macro __NR_SYSCALL_MASK for + Arm, which is not a syscall but matches the pattern used for syscall + macro names. + + Add __NR_SYSCALL_MASK to the names filtered out in the code dealing + with syscall lists, update syscall-names.list for the new syscall and + regenerate the arch-syscall.h headers with build-many-glibcs.py + update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.15. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index fd98893b0e..1a74d090b7 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.14. +-kernel 5.14 ++# The list of system calls is current as of Linux 5.15. ++kernel 5.15 + + FAST_atomic_update + FAST_cmpxchg +@@ -440,6 +440,7 @@ preadv + preadv2 + prlimit64 + process_madvise ++process_mrelease + process_vm_readv + process_vm_writev + prof diff --git a/glibc-rh2080349-5.patch b/glibc-rh2080349-5.patch new file mode 100644 index 0000000..b042917 --- /dev/null +++ b/glibc-rh2080349-5.patch @@ -0,0 +1,37 @@ +commit 4997a533ae4b51ef66a6b68862b7578a7acb82df +Author: Joseph Myers +Date: Thu Jan 13 22:18:13 2022 +0000 + + Update syscall lists for Linux 5.16 + + Linux 5.16 has one new syscall, futex_waitv. Update + syscall-names.list and regenerate the arch-syscall.h headers with + build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.16. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index c80a9a59cb..6421806110 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.15. +-kernel 5.15 ++# The list of system calls is current as of Linux 5.16. ++kernel 5.16 + + FAST_atomic_update + FAST_cmpxchg +@@ -146,6 +146,7 @@ ftruncate + ftruncate64 + futex + futex_time64 ++futex_waitv + futimesat + get_kernel_syms + get_mempolicy diff --git a/glibc-rh2080349-6.patch b/glibc-rh2080349-6.patch new file mode 100644 index 0000000..333f362 --- /dev/null +++ b/glibc-rh2080349-6.patch @@ -0,0 +1,37 @@ +commit 8ef9196b26793830515402ea95aca2629f7721ec +Author: Joseph Myers +Date: Wed Mar 23 17:11:56 2022 +0000 + + Update syscall lists for Linux 5.17 + + Linux 5.17 has one new syscall, set_mempolicy_home_node. Update + syscall-names.list and regenerate the arch-syscall.h headers with + build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.17. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 6421806110..b8c0b0c586 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.16. +-kernel 5.16 ++# The list of system calls is current as of Linux 5.17. ++kernel 5.17 + + FAST_atomic_update + FAST_cmpxchg +@@ -524,6 +524,7 @@ sendmmsg + sendmsg + sendto + set_mempolicy ++set_mempolicy_home_node + set_robust_list + set_thread_area + set_tid_address diff --git a/glibc-rh2080349-7.patch b/glibc-rh2080349-7.patch new file mode 100644 index 0000000..067f10e --- /dev/null +++ b/glibc-rh2080349-7.patch @@ -0,0 +1,28 @@ +commit 3d9926663cba19f40d26d8a8ab3b2a7cc09ffb13 +Author: Joseph Myers +Date: Wed May 25 14:37:28 2022 +0000 + + Update syscall-names.list for Linux 5.18 + + Linux 5.18 has no new syscalls. Update the version number in + syscall-names.list to reflect that it is still current for 5.18. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.18. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index b8c0b0c586..6c7b2f7011 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.17. +-kernel 5.17 ++# The list of system calls is current as of Linux 5.18. ++kernel 5.18 + + FAST_atomic_update + FAST_cmpxchg diff --git a/glibc-rh2080349-8.patch b/glibc-rh2080349-8.patch new file mode 100644 index 0000000..5e6fa9f --- /dev/null +++ b/glibc-rh2080349-8.patch @@ -0,0 +1,20 @@ +commit 9dde3a24f132090fa8f88d6eaa2bc4c48f2e942f +Author: Stafford Horne +Date: Sat May 23 12:41:31 2020 +0900 + + linux/syscalls: Add or1k_atomic syscall for OpenRISC + + Reviewed-by: Adhemerval Zanella + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 42701ce583..c80a9a59cb 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -304,6 +304,7 @@ open_by_handle_at + open_tree + openat + openat2 ++or1k_atomic + osf_adjtime + osf_afs_syscall + osf_alt_plock diff --git a/glibc-rh2080349-9.patch b/glibc-rh2080349-9.patch new file mode 100644 index 0000000..080811e --- /dev/null +++ b/glibc-rh2080349-9.patch @@ -0,0 +1,10 @@ +diff -Nrup a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +--- a/sysdeps/unix/sysv/linux/syscall-names.list 2022-07-18 10:44:38.791332453 -0400 ++++ b/sysdeps/unix/sysv/linux/syscall-names.list 2022-07-18 11:02:51.054663735 -0400 +@@ -1,5 +1,5 @@ + # List of all known Linux system calls. +-# Copyright (C) 2017-2021 Free Software Foundation, Inc. ++# Copyright (C) 2017-2022 Free Software Foundation, Inc. + # This file is part of the GNU C Library. + # + # The GNU C Library is free software; you can redistribute it and/or diff --git a/glibc-rh2086853.patch b/glibc-rh2086853.patch new file mode 100644 index 0000000..d11e4cb --- /dev/null +++ b/glibc-rh2086853.patch @@ -0,0 +1,30 @@ +commit 61a87530108ec9181e1b18a9b727ec3cc3ba7532 +Author: Siddhesh Poyarekar +Date: Fri May 13 10:01:47 2022 +0530 + + fortify: Ensure that __glibc_fortify condition is a constant [BZ #29141] + + The fix c8ee1c85 introduced a -1 check for object size without also + checking that object size is a constant. Because of this, the tree + optimizer passes in gcc fail to fold away one of the branches in + __glibc_fortify and trips on a spurious Wstringop-overflow. The warning + itself is incorrect and the branch does go away eventually in DCE in the + rtl passes in gcc, but the constant check is a helpful hint to simplify + code early, so add it in. + + Resolves: BZ #29141 + Signed-off-by: Siddhesh Poyarekar + +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 404496c7d6da4fb3..f3d7efdd2a9320f7 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -145,7 +145,7 @@ + /* 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, or unknown (-1) */ + #define __glibc_safe_or_unknown_len(__l, __s, __osz) \ +- ((__osz) == (__SIZE_TYPE__) -1 \ ++ ((__builtin_constant_p (__osz) && (__osz) == (__SIZE_TYPE__) -1) \ + || (__glibc_unsigned_or_positive (__l) \ + && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ + (__s), (__osz))) \ diff --git a/glibc-rh2093457-1.patch b/glibc-rh2089247-1.patch similarity index 100% rename from glibc-rh2093457-1.patch rename to glibc-rh2089247-1.patch diff --git a/glibc-rh2093457-2.patch b/glibc-rh2089247-2.patch similarity index 100% rename from glibc-rh2093457-2.patch rename to glibc-rh2089247-2.patch diff --git a/glibc-rh2093457-3.patch b/glibc-rh2089247-3.patch similarity index 100% rename from glibc-rh2093457-3.patch rename to glibc-rh2089247-3.patch diff --git a/glibc-rh2093457-4.patch b/glibc-rh2089247-4.patch similarity index 100% rename from glibc-rh2093457-4.patch rename to glibc-rh2089247-4.patch diff --git a/glibc-rh2093457-5.patch b/glibc-rh2089247-5.patch similarity index 100% rename from glibc-rh2093457-5.patch rename to glibc-rh2089247-5.patch diff --git a/glibc-rh2093457-6.patch b/glibc-rh2089247-6.patch similarity index 100% rename from glibc-rh2093457-6.patch rename to glibc-rh2089247-6.patch diff --git a/glibc-rh2094540.patch b/glibc-rh2091553.patch similarity index 100% rename from glibc-rh2094540.patch rename to glibc-rh2091553.patch diff --git a/glibc-rh2096189-1.patch b/glibc-rh2096189-1.patch new file mode 100644 index 0000000..33cc310 --- /dev/null +++ b/glibc-rh2096189-1.patch @@ -0,0 +1,67 @@ +commit 62a321b12d0e397af88fa422db65079332f971dc +Author: Florian Weimer +Date: Fri Jun 24 18:16:41 2022 +0200 + + support: Change non-address output format of support_format_dns_packet + + It makes sense to include the owner name (LHS) and record type in the + output, so that they can be checked for correctness. + + Reviewed-by: Carlos O'Donell + +diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c +index 1170eafb0f008fee..ef862bc4c8d14af0 100644 +--- a/support/support_format_dns_packet.c ++++ b/support/support_format_dns_packet.c +@@ -101,6 +101,17 @@ extract_name (struct in_buffer full, struct in_buffer *in, struct dname *value) + return true; + } + ++static void ++extract_name_data (struct in_buffer full, struct in_buffer *rdata, ++ const struct dname *owner, const char *typename, FILE *out) ++{ ++ struct dname name; ++ if (extract_name (full, rdata, &name)) ++ fprintf (out, "data: %s %s %s\n", owner->name, typename, name.name); ++ else ++ fprintf (out, "error: malformed CNAME/PTR record\n"); ++} ++ + char * + support_format_dns_packet (const unsigned char *buffer, size_t length) + { +@@ -206,14 +217,11 @@ support_format_dns_packet (const unsigned char *buffer, size_t length) + } + break; + case T_CNAME: ++ extract_name_data (full, &rdata, &rname, "CNAME", mem.out); ++ break; + case T_PTR: +- { +- struct dname name; +- if (extract_name (full, &rdata, &name)) +- fprintf (mem.out, "name: %s\n", name.name); +- else +- fprintf (mem.out, "error: malformed CNAME/PTR record\n"); +- } ++ extract_name_data (full, &rdata, &rname, "PTR", mem.out); ++ break; + } + } + +diff --git a/support/tst-support_format_dns_packet.c b/support/tst-support_format_dns_packet.c +index b1135eebc6c02d55..35f475fe86177772 100644 +--- a/support/tst-support_format_dns_packet.c ++++ b/support/tst-support_format_dns_packet.c +@@ -85,8 +85,8 @@ test_multiple_cnames (void) + "\xc0\x00\x02\x01"; + check_packet (packet, sizeof (packet) - 1, __func__, + "name: www.example\n" +- "name: www1.example\n" +- "name: www2.example\n" ++ "data: www.example CNAME www1.example\n" ++ "data: www1.example CNAME www2.example\n" + "address: 192.0.2.1\n"); + } + diff --git a/glibc-rh2096189-2.patch b/glibc-rh2096189-2.patch new file mode 100644 index 0000000..201f089 --- /dev/null +++ b/glibc-rh2096189-2.patch @@ -0,0 +1,957 @@ +commit f282cdbe7f436c75864e5640a409a10485e9abb2 +Author: Florian Weimer +Date: Fri Jun 24 18:16:41 2022 +0200 + + resolv: Implement no-aaaa stub resolver option + + Reviewed-by: Carlos O'Donell + +Conflicts: + resolv/Makefile + (missing partial libresolv integration downstream) + resolv/res-noaaaa.c + (call ns_name_skip instead of __ns_name_skip (not available + downstream) and ns_name_unpack instead of __ns_name_unpack + (avoid PLT)) + resolv/res_debug.c + resolv/res_init.c + resolv/resolv.h + resolv/tst-resolv-res_init-skeleton.c + (missing trust-ad support downstream) + +diff --git a/resolv/Makefile b/resolv/Makefile +index cee5225f8933f245..ab8ad49b5318ad41 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -57,6 +57,7 @@ tests += \ + tst-resolv-binary \ + tst-resolv-edns \ + tst-resolv-network \ ++ tst-resolv-noaaaa \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ +@@ -110,7 +111,7 @@ libresolv-routines := res_comp res_debug \ + res_data res_mkquery res_query res_send \ + inet_net_ntop inet_net_pton inet_neta base64 \ + ns_parse ns_name ns_netint ns_ttl ns_print \ +- ns_samedomain ns_date res_enable_icmp \ ++ ns_samedomain ns_date res_enable_icmp res-noaaaa \ + compat-hooks compat-gethnamaddr + + libanl-routines := gai_cancel gai_error gai_misc gai_notify gai_suspend \ +@@ -200,6 +201,7 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ + $(shared-thread-library) + $(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \ + $(shared-thread-library) ++$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 99c3b61e1cee4d42..ff0a0b6f7f1f4703 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -123,6 +123,14 @@ static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); ++static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1, ++ int anslen1, ++ const char *qname, ++ struct gaih_addrtuple **pat, ++ char *buffer, size_t buflen, ++ int *errnop, int *h_errnop, ++ int32_t *ttlp); ++ + + static enum nss_status gethostbyname3_context (struct resolv_context *ctx, + const char *name, int af, +@@ -367,17 +375,31 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + int resplen2 = 0; + int ans2p_malloced = 0; + ++ + int olderr = errno; +- int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, ++ int n; ++ ++ if ((ctx->resp->options & RES_NOAAAA) == 0) ++ { ++ n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, + host_buffer.buf->buf, 2048, &host_buffer.ptr, + &ans2p, &nans2p, &resplen2, &ans2p_malloced); +- if (n >= 0) +- { +- status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p, +- resplen2, name, pat, buffer, buflen, +- errnop, herrnop, ttlp); ++ if (n >= 0) ++ status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p, ++ resplen2, name, pat, buffer, buflen, ++ errnop, herrnop, ttlp); + } + else ++ { ++ n = __res_context_search (ctx, name, C_IN, T_A, ++ host_buffer.buf->buf, 2048, NULL, ++ NULL, NULL, NULL, NULL); ++ if (n >= 0) ++ status = gaih_getanswer_noaaaa (host_buffer.buf, n, ++ name, pat, buffer, buflen, ++ errnop, herrnop, ttlp); ++ } ++ if (n < 0) + { + switch (errno) + { +@@ -1386,3 +1408,21 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + + return status; + } ++ ++/* Variant of gaih_getanswer without a second (AAAA) response. */ ++static enum nss_status ++gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname, ++ struct gaih_addrtuple **pat, ++ char *buffer, size_t buflen, ++ int *errnop, int *h_errnop, int32_t *ttlp) ++{ ++ int first = 1; ++ ++ enum nss_status status = NSS_STATUS_NOTFOUND; ++ if (anslen1 > 0) ++ status = gaih_getanswer_slice (answer1, anslen1, qname, ++ &pat, &buffer, &buflen, ++ errnop, h_errnop, ttlp, ++ &first); ++ return status; ++} +diff --git a/resolv/res-noaaaa.c b/resolv/res-noaaaa.c +new file mode 100644 +index 0000000000000000..e2a13cf38a74c160 +--- /dev/null ++++ b/resolv/res-noaaaa.c +@@ -0,0 +1,143 @@ ++/* Implement suppression of AAAA queries. ++ 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 ++ ++/* Returns true if the question type at P matches EXPECTED, and the ++ class is IN. */ ++static bool ++qtype_matches (const unsigned char *p, int expected) ++{ ++ /* This assumes that T_A/C_IN constants are less than 256, which ++ they are. */ ++ return p[0] == 0 && p[1] == expected && p[2] == 0 && p[3] == C_IN; ++} ++ ++/* Handle RES_NOAAAA translation of AAAA queries. To produce a Name ++ Error (NXDOMAIN) repsonse for domain names that do not exist, it is ++ still necessary to send a query. Using question type A is a ++ conservative choice. In the returned answer, it is necessary to ++ switch back the question type to AAAA. */ ++bool ++__res_handle_no_aaaa (struct resolv_context *ctx, ++ const unsigned char *buf, int buflen, ++ unsigned char *ans, int anssiz, int *result) ++{ ++ /* AAAA mode is not active, or the query looks invalid (will not be ++ able to be parsed). */ ++ if ((ctx->resp->options & RES_NOAAAA) == 0 ++ || buflen <= sizeof (HEADER)) ++ return false; ++ ++ /* The replacement A query is produced here. */ ++ struct ++ { ++ HEADER header; ++ unsigned char question[NS_MAXCDNAME + 4]; ++ } replacement; ++ memcpy (&replacement.header, buf, sizeof (replacement.header)); ++ ++ if (replacement.header.qr ++ || replacement.header.opcode != 0 ++ || replacement.header.rcode != 0 ++ || ntohs (replacement.header.qdcount) != 1 ++ || ntohs (replacement.header.ancount) != 0 ++ || ntohs (replacement.header.nscount) != 0) ++ /* Not a well-formed question. Let the core resolver code produce ++ the proper error. */ ++ return false; ++ ++ /* Disable EDNS0. */ ++ replacement.header.arcount = htons (0); ++ ++ /* Extract the QNAME. */ ++ int ret = ns_name_unpack (buf, buf + buflen, buf + sizeof (HEADER), ++ replacement.question, NS_MAXCDNAME); ++ if (ret < 0) ++ /* Format error. */ ++ return false; ++ ++ /* Compute the end of the question name. */ ++ const unsigned char *after_question = buf + sizeof (HEADER) + ret; ++ ++ /* Check that we are dealing with an AAAA query. */ ++ if (buf + buflen - after_question < 4 ++ || !qtype_matches (after_question, T_AAAA)) ++ return false; ++ ++ /* Find the place to store the type/class data in the replacement ++ query. */ ++ after_question = replacement.question; ++ /* This cannot fail because ns_name_unpack above produced a valid ++ domain name. */ ++ (void) ns_name_skip (&after_question, &replacement.question[NS_MAXCDNAME]); ++ unsigned char *start_of_query = (unsigned char *) &replacement; ++ const unsigned char *end_of_query = after_question + 4; ++ ++ /* Produce an A/IN query. */ ++ { ++ unsigned char *p = (unsigned char *) after_question; ++ p[0] = 0; ++ p[1] = T_A; ++ p[2] = 0; ++ p[3] = C_IN; ++ } ++ ++ /* Clear the output buffer, to avoid reading undefined data when ++ rewriting the result from A to AAAA. */ ++ memset (ans, 0, anssiz); ++ ++ /* Always perform the message translation, independent of the error ++ code. */ ++ ret = __res_context_send (ctx, ++ start_of_query, end_of_query - start_of_query, ++ NULL, 0, ans, anssiz, ++ NULL, NULL, NULL, NULL, NULL); ++ ++ /* Patch in the AAAA question type if there is room and the A query ++ type was received. */ ++ after_question = ans + sizeof (HEADER); ++ if (ns_name_skip (&after_question, ans + anssiz) == 0 ++ && ans + anssiz - after_question >= 4 ++ && qtype_matches (after_question, T_A)) ++ { ++ ((unsigned char *) after_question)[1] = T_AAAA; ++ ++ /* Create an aligned copy of the header. Hide all data except ++ the question from the response. Put back the header. There is ++ no need to change the response code. The zero answer count turns ++ a positive response with data into a no-data response. */ ++ memcpy (&replacement.header, ans, sizeof (replacement.header)); ++ replacement.header.ancount = htons (0); ++ replacement.header.nscount = htons (0); ++ replacement.header.arcount = htons (0); ++ memcpy (ans, &replacement.header, sizeof (replacement.header)); ++ ++ /* Truncate the reply. */ ++ if (ret <= 0) ++ *result = ret; ++ else ++ *result = after_question - ans + 4; ++ } ++ ++ return true; ++} +diff --git a/resolv/res_debug.c b/resolv/res_debug.c +index 7681ad4639d8a7bc..43b3b1bfe4afdcaf 100644 +--- a/resolv/res_debug.c ++++ b/resolv/res_debug.c +@@ -615,6 +615,7 @@ p_option(u_long option) { + case RES_USE_DNSSEC: return "dnssec"; + case RES_NOTLDQUERY: return "no-tld-query"; + case RES_NORELOAD: return "no-reload"; ++ case RES_NOAAAA: return "no-aaaa"; + /* XXX nonreentrant */ + default: sprintf(nbuf, "?0x%lx?", (u_long)option); + return (nbuf); +diff --git a/resolv/res_init.c b/resolv/res_init.c +index bb99ddeec4d6d47f..20434bfe147a3fb5 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -694,7 +694,8 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options) + { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY }, + { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY }, + { STRnLEN ("no-reload"), 0, RES_NORELOAD }, +- { STRnLEN ("use-vc"), 0, RES_USEVC } ++ { STRnLEN ("use-vc"), 0, RES_USEVC }, ++ { STRnLEN ("no-aaaa"), 0, RES_NOAAAA }, + }; + #define noptions (sizeof (options) / sizeof (options[0])) + for (int i = 0; i < noptions; ++i) +diff --git a/resolv/res_query.c b/resolv/res_query.c +index ebbe5a6a4ed86abe..d94966a47c3dac90 100644 +--- a/resolv/res_query.c ++++ b/resolv/res_query.c +@@ -204,10 +204,26 @@ __res_context_query (struct resolv_context *ctx, const char *name, + free (buf); + return (n); + } +- assert (answerp == NULL || (void *) *answerp == (void *) answer); +- n = __res_context_send (ctx, query1, nquery1, query2, nquery2, answer, +- anslen, answerp, answerp2, nanswerp2, resplen2, +- answerp2_malloced); ++ ++ /* Suppress AAAA lookups if required. __res_handle_no_aaaa ++ checks RES_NOAAAA first, so avoids parsing the ++ just-generated query packet in most cases. nss_dns avoids ++ using T_QUERY_A_AND_AAAA in RES_NOAAAA mode, so there is no ++ need to handle it here. */ ++ if (type == T_AAAA && __res_handle_no_aaaa (ctx, query1, nquery1, ++ answer, anslen, &n)) ++ /* There must be no second query for AAAA queries. The code ++ below is still needed to translate NODATA responses. */ ++ assert (query2 == NULL); ++ else ++ { ++ assert (answerp == NULL || (void *) *answerp == (void *) answer); ++ n = __res_context_send (ctx, query1, nquery1, query2, nquery2, ++ answer, anslen, ++ answerp, answerp2, nanswerp2, resplen2, ++ answerp2_malloced); ++ } ++ + if (use_malloc) + free (buf); + if (n < 0) { +diff --git a/resolv/res_send.c b/resolv/res_send.c +index 55e7fa438e7baac1..2e676bff0edf0cdc 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -550,8 +550,13 @@ context_send_common (struct resolv_context *ctx, + RES_SET_H_ERRNO (&_res, NETDB_INTERNAL); + return -1; + } +- int result = __res_context_send (ctx, buf, buflen, NULL, 0, ans, anssiz, +- NULL, NULL, NULL, NULL, NULL); ++ ++ int result; ++ if (__res_handle_no_aaaa (ctx, buf, buflen, ans, anssiz, &result)) ++ return result; ++ ++ result = __res_context_send (ctx, buf, buflen, NULL, 0, ans, anssiz, ++ NULL, NULL, NULL, NULL, NULL); + __resolv_context_put (ctx); + return result; + } +diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h +index 0878f6830f2a08ff..4564f6ba2f7202f5 100644 +--- a/resolv/resolv-internal.h ++++ b/resolv/resolv-internal.h +@@ -79,6 +79,14 @@ int __res_context_send (struct resolv_context *, const unsigned char *, int, + int, unsigned char **, unsigned char **, + int *, int *, int *) attribute_hidden; + ++/* Return true if the query has been handled in RES_NOAAAA mode. For ++ that, RES_NOAAAA must be active, and the question type must be AAAA. ++ The caller is expected to return *RESULT as the return value. */ ++bool __res_handle_no_aaaa (struct resolv_context *ctx, ++ const unsigned char *buf, int buflen, ++ unsigned char *ans, int anssiz, int *result) ++ attribute_hidden; ++ + /* Internal function similar to res_hostalias. */ + const char *__res_context_hostalias (struct resolv_context *, + const char *, char *, size_t); +diff --git a/resolv/resolv.h b/resolv/resolv.h +index 80a523e5e40982ad..0f7298f395a829d3 100644 +--- a/resolv/resolv.h ++++ b/resolv/resolv.h +@@ -135,6 +135,7 @@ struct res_sym { + #define RES_NOTLDQUERY 0x01000000 /* Do not look up unqualified name + as a TLD. */ + #define RES_NORELOAD 0x02000000 /* No automatic configuration reload. */ ++#define RES_NOAAAA 0x08000000 /* Suppress AAAA queries. */ + + #define RES_DEFAULT (RES_RECURSE|RES_DEFNAMES|RES_DNSRCH) + +diff --git a/resolv/tst-resolv-noaaaa.c b/resolv/tst-resolv-noaaaa.c +new file mode 100644 +index 0000000000000000..56b25f88a58ad286 +--- /dev/null ++++ b/resolv/tst-resolv-noaaaa.c +@@ -0,0 +1,533 @@ ++/* Test the RES_NOAAAA resolver option. ++ 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 ++ ++/* Used to keep track of the number of queries. */ ++static volatile unsigned int queries; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* Each test should only send one query. */ ++ ++queries; ++ TEST_COMPARE (queries, 1); ++ ++ /* AAAA queries are supposed to be disabled. */ ++ TEST_VERIFY (qtype != T_AAAA); ++ TEST_COMPARE (qclass, C_IN); ++ ++ /* The only other query type besides A is PTR. */ ++ if (qtype != T_A) ++ TEST_COMPARE (qtype, T_PTR); ++ ++ int an, ns, ar; ++ char *tail; ++ if (sscanf (qname, "an%d.ns%d.ar%d.%ms", &an, &ns, &ar, &tail) != 4) ++ FAIL_EXIT1 ("invalid QNAME: %s\n", qname); ++ TEST_COMPARE_STRING (tail, "example"); ++ free (tail); ++ ++ if (an < 0 || ns < 0 || ar < 0) ++ { ++ struct resolv_response_flags flags = { .rcode = NXDOMAIN, }; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ return; ++ } ++ ++ struct resolv_response_flags flags = {}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ ++ resolv_response_section (b, ns_s_an); ++ for (int i = 0; i < an; ++i) ++ { ++ resolv_response_open_record (b, qname, qclass, qtype, 60); ++ switch (qtype) ++ { ++ case T_A: ++ char ipv4[4] = {192, 0, 2, i + 1}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ break; ++ ++ case T_PTR: ++ char *name = xasprintf ("ptr-%d", i); ++ resolv_response_add_name (b, name); ++ free (name); ++ break; ++ } ++ resolv_response_close_record (b); ++ } ++ ++ resolv_response_section (b, ns_s_ns); ++ for (int i = 0; i < ns; ++i) ++ { ++ resolv_response_open_record (b, qname, qclass, T_NS, 60); ++ char *name = xasprintf ("ns%d.example.net", i); ++ resolv_response_add_name (b, name); ++ free (name); ++ resolv_response_close_record (b); ++ } ++ ++ resolv_response_section (b, ns_s_ar); ++ int addr = 1; ++ for (int i = 0; i < ns; ++i) ++ { ++ char *name = xasprintf ("ns%d.example.net", i); ++ for (int j = 0; j < ar; ++j) ++ { ++ resolv_response_open_record (b, name, qclass, T_A, 60); ++ char ipv4[4] = {192, 0, 2, addr}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ resolv_response_close_record (b); ++ ++ resolv_response_open_record (b, name, qclass, T_AAAA, 60); ++ char ipv6[16] ++ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, addr}; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ resolv_response_close_record (b); ++ ++ ++addr; ++ } ++ free (name); ++ } ++} ++ ++/* Number of modes. Lowest bit encodes *n* function vs implicit _res ++ argument. The mode numbers themselves are arbitrary. */ ++enum { mode_count = 8 }; ++ ++/* res_send-like modes do not perform error translation. */ ++enum { first_send_mode = 6 }; ++ ++static int ++libresolv_query (unsigned int mode, const char *qname, uint16_t qtype, ++ unsigned char *buf, size_t buflen) ++{ ++ int saved_errno = errno; ++ ++ TEST_VERIFY_EXIT (mode < mode_count); ++ ++ switch (mode) ++ { ++ case 0: ++ return res_query (qname, C_IN, qtype, buf, buflen); ++ case 1: ++ return res_nquery (&_res, qname, C_IN, qtype, buf, buflen); ++ case 2: ++ return res_search (qname, C_IN, qtype, buf, buflen); ++ case 3: ++ return res_nsearch (&_res, qname, C_IN, qtype, buf, buflen); ++ case 4: ++ return res_querydomain (qname, "", C_IN, qtype, buf, buflen); ++ case 5: ++ return res_nquerydomain (&_res, qname, "", C_IN, qtype, buf, buflen); ++ case 6: ++ { ++ unsigned char querybuf[512]; ++ int ret = res_mkquery (QUERY, qname, C_IN, qtype, ++ NULL, 0, NULL, querybuf, sizeof (querybuf)); ++ TEST_VERIFY_EXIT (ret > 0); ++ errno = saved_errno; ++ return res_send (querybuf, ret, buf, buflen); ++ } ++ case 7: ++ { ++ unsigned char querybuf[512]; ++ int ret = res_nmkquery (&_res, QUERY, qname, C_IN, qtype, ++ NULL, 0, NULL, querybuf, sizeof (querybuf)); ++ TEST_VERIFY_EXIT (ret > 0); ++ errno = saved_errno; ++ return res_nsend (&_res, querybuf, ret, buf, buflen); ++ } ++ } ++ __builtin_unreachable (); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ _res.options |= RES_NOAAAA; ++ ++ check_hostent ("an1.ns2.ar1.example", ++ gethostbyname ("an1.ns2.ar1.example"), ++ "name: an1.ns2.ar1.example\n" ++ "address: 192.0.2.1\n"); ++ queries = 0; ++ check_hostent ("an0.ns2.ar1.example", ++ gethostbyname ("an0.ns2.ar1.example"), ++ "error: NO_ADDRESS\n"); ++ queries = 0; ++ check_hostent ("an-1.ns2.ar1.example", ++ gethostbyname ("an-1.ns2.ar1.example"), ++ "error: HOST_NOT_FOUND\n"); ++ queries = 0; ++ ++ check_hostent ("an1.ns2.ar1.example AF_INET", ++ gethostbyname2 ("an1.ns2.ar1.example", AF_INET), ++ "name: an1.ns2.ar1.example\n" ++ "address: 192.0.2.1\n"); ++ queries = 0; ++ check_hostent ("an0.ns2.ar1.example AF_INET", ++ gethostbyname2 ("an0.ns2.ar1.example", AF_INET), ++ "error: NO_ADDRESS\n"); ++ queries = 0; ++ check_hostent ("an-1.ns2.ar1.example AF_INET", ++ gethostbyname2 ("an-1.ns2.ar1.example", AF_INET), ++ "error: HOST_NOT_FOUND\n"); ++ queries = 0; ++ ++ check_hostent ("an1.ns2.ar1.example AF_INET6", ++ gethostbyname2 ("an1.ns2.ar1.example", AF_INET6), ++ "error: NO_ADDRESS\n"); ++ queries = 0; ++ check_hostent ("an0.ns2.ar1.example AF_INET6", ++ gethostbyname2 ("an0.ns2.ar1.example", AF_INET6), ++ "error: NO_ADDRESS\n"); ++ queries = 0; ++ check_hostent ("an-1.ns2.ar1.example AF_INET6", ++ gethostbyname2 ("an-1.ns2.ar1.example", AF_INET6), ++ "error: HOST_NOT_FOUND\n"); ++ queries = 0; ++ ++ /* Multiple addresses. */ ++ check_hostent ("an2.ns0.ar0.example", ++ gethostbyname ("an2.ns0.ar0.example"), ++ "name: an2.ns0.ar0.example\n" ++ "address: 192.0.2.1\n" ++ "address: 192.0.2.2\n"); ++ queries = 0; ++ check_hostent ("an2.ns0.ar0.example AF_INET6", ++ gethostbyname2 ("an2.ns0.ar0.example", AF_INET6), ++ "error: NO_ADDRESS\n"); ++ queries = 0; ++ ++ /* getaddrinfo checks with one address. */ ++ struct addrinfo *ai; ++ int ret; ++ ret = getaddrinfo ("an1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an1.ns2.ar1.example (AF_INET)", ai, ret, ++ "address: STREAM/TCP 192.0.2.1 80\n"); ++ freeaddrinfo (ai); ++ queries = 0; ++ ret = getaddrinfo ("an1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET6, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an1.ns2.ar1.example (AF_INET6)", ai, ret, ++ "error: No address associated with hostname\n"); ++ queries = 0; ++ ret = getaddrinfo ("an1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an1.ns2.ar1.example (AF_UNSPEC)", ai, ret, ++ "address: STREAM/TCP 192.0.2.1 80\n"); ++ freeaddrinfo (ai); ++ queries = 0; ++ ++ /* getaddrinfo checks with three addresses. */ ++ ret = getaddrinfo ("an3.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an3.ns2.ar1.example (AF_INET)", ai, ret, ++ "address: STREAM/TCP 192.0.2.1 80\n" ++ "address: STREAM/TCP 192.0.2.2 80\n" ++ "address: STREAM/TCP 192.0.2.3 80\n"); ++ freeaddrinfo (ai); ++ queries = 0; ++ ret = getaddrinfo ("an3.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET6, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an3.ns2.ar1.example (AF_INET6)", ai, ret, ++ "error: No address associated with hostname\n"); ++ queries = 0; ++ ret = getaddrinfo ("an3.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an3.ns2.ar1.example (AF_UNSPEC)", ai, ret, ++ "address: STREAM/TCP 192.0.2.1 80\n" ++ "address: STREAM/TCP 192.0.2.2 80\n" ++ "address: STREAM/TCP 192.0.2.3 80\n"); ++ freeaddrinfo (ai); ++ queries = 0; ++ ++ /* getaddrinfo checks with no address. */ ++ ret = getaddrinfo ("an0.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an0.ns2.ar1.example (AF_INET)", ai, ret, ++ "error: No address associated with hostname\n"); ++ queries = 0; ++ ret = getaddrinfo ("an0.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET6, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an0.ns2.ar1.example (AF_INET6)", ai, ret, ++ "error: No address associated with hostname\n"); ++ queries = 0; ++ ret = getaddrinfo ("an0.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an-1.ns2.ar1.example (AF_UNSPEC)", ai, ret, ++ "error: No address associated with hostname\n"); ++ queries = 0; ++ ++ /* getaddrinfo checks with NXDOMAIN. */ ++ ret = getaddrinfo ("an-1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an-1.ns2.ar1.example (AF_INET)", ai, ret, ++ "error: Name or service not known\n"); ++ queries = 0; ++ ret = getaddrinfo ("an-1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET6, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an-1.ns2.ar1.example (AF_INET6)", ai, ret, ++ "error: Name or service not known\n"); ++ queries = 0; ++ ret = getaddrinfo ("an-1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an-1.ns2.ar1.example (AF_UNSPEC)", ai, ret, ++ "error: Name or service not known\n"); ++ queries = 0; ++ ++ for (unsigned int mode = 0; mode < mode_count; ++mode) ++ { ++ unsigned char *buf; ++ int ret; ++ ++ /* Response for A. */ ++ buf = malloc (512); ++ ret = libresolv_query (mode, "an1.ns2.ar1.example", T_A, buf, 512); ++ TEST_VERIFY_EXIT (ret > 0); ++ check_dns_packet ("an1.ns2.ar1.example A", buf, ret, ++ "name: an1.ns2.ar1.example\n" ++ "address: 192.0.2.1\n"); ++ free (buf); ++ queries = 0; ++ ++ /* NODATA response for A. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an0.ns2.ar1.example", T_A, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, NO_ADDRESS); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, 0); ++ check_dns_packet ("an1.ns2.ar1.example A", buf, ret, ++ "name: an0.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* NXDOMAIN response for A. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an-1.ns2.ar1.example", T_A, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, NXDOMAIN); ++ check_dns_packet ("an1.ns2.ar1.example A", buf, ret, ++ "name: an-1.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* Response for PTR. */ ++ buf = malloc (512); ++ ret = libresolv_query (mode, "an1.ns2.ar1.example", T_PTR, buf, 512); ++ TEST_VERIFY_EXIT (ret > 0); ++ check_dns_packet ("an1.ns2.ar1.example PTR", buf, ret, ++ "name: an1.ns2.ar1.example\n" ++ "data: an1.ns2.ar1.example PTR ptr-0\n"); ++ free (buf); ++ queries = 0; ++ ++ /* NODATA response for PTR. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an0.ns2.ar1.example", T_PTR, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, NO_ADDRESS); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, 0); ++ check_dns_packet ("an1.ns2.ar1.example PTR", buf, ret, ++ "name: an0.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* NXDOMAIN response for PTR. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an-1.ns2.ar1.example", T_PTR, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, NXDOMAIN); ++ check_dns_packet ("an1.ns2.ar1.example PTR", buf, ret, ++ "name: an-1.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* NODATA response for AAAA. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an1.ns2.ar1.example", T_AAAA, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, NO_ADDRESS); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, 0); ++ check_dns_packet ("an1.ns2.ar1.example A", buf, ret, ++ "name: an1.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* NODATA response for AAAA (original is already NODATA). */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an0.ns2.ar1.example", T_AAAA, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, NO_ADDRESS); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, 0); ++ check_dns_packet ("an0.ns2.ar1.example A", buf, ret, ++ "name: an0.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* NXDOMAIN response. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an-1.ns2.ar1.example", T_AAAA, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, NXDOMAIN); ++ check_dns_packet ("an-1.ns2.ar1.example A", buf, ret, ++ "name: an-1.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ } ++ ++ resolv_test_end (obj); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c +index a5061e6d4fb98311..7d8758a99e180d97 100644 +--- a/resolv/tst-resolv-res_init-skeleton.c ++++ b/resolv/tst-resolv-res_init-skeleton.c +@@ -129,6 +129,7 @@ print_resp (FILE *fp, res_state resp) + "single-request-reopen"); + print_option_flag (fp, &options, RES_NOTLDQUERY, "no-tld-query"); + print_option_flag (fp, &options, RES_NORELOAD, "no-reload"); ++ print_option_flag (fp, &options, RES_NOAAAA, "no-aaaa"); + fputc ('\n', fp); + if (options != 0) + fprintf (fp, "; error: unresolved option bits: 0x%x\n", options); +@@ -713,6 +714,15 @@ struct test_case test_cases[] = + "nameserver 192.0.2.1\n" + "; nameserver[0]: [192.0.2.1]:53\n" + }, ++ {.name = "no-aaaa flag", ++ .conf = "options no-aaaa\n" ++ "nameserver 192.0.2.1\n", ++ .expected = "options no-aaaa\n" ++ "search example.com\n" ++ "; search[0]: example.com\n" ++ "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n" ++ }, + { NULL } + }; + diff --git a/glibc-rh2096189-3.patch b/glibc-rh2096189-3.patch new file mode 100644 index 0000000..604afa4 --- /dev/null +++ b/glibc-rh2096189-3.patch @@ -0,0 +1,44 @@ +commit 77536da3dea5af4d1859e4e754f07f47cf8d7d4c +Author: Florian Weimer +Date: Fri Jun 24 19:38:14 2022 +0200 + + resolv/tst-resolv-noaaaa: Support building for older C standards + + This avoids a compilation error: + + tst-resolv-noaaaa.c: In function 'response': + tst-resolv-noaaaa.c:74:11: error: a label can only be part of a statement and a declaration is not a statement + char ipv4[4] = {192, 0, 2, i + 1}; + ^~~~ + tst-resolv-noaaaa.c:79:11: error: a label can only be part of a statement and a declaration is not a statement + char *name = xasprintf ("ptr-%d", i); + ^~~~ + +diff --git a/resolv/tst-resolv-noaaaa.c b/resolv/tst-resolv-noaaaa.c +index 56b25f88a58ad286..6e0c6b6fb809e245 100644 +--- a/resolv/tst-resolv-noaaaa.c ++++ b/resolv/tst-resolv-noaaaa.c +@@ -71,14 +71,18 @@ response (const struct resolv_response_context *ctx, + switch (qtype) + { + case T_A: +- char ipv4[4] = {192, 0, 2, i + 1}; +- resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ { ++ char ipv4[4] = {192, 0, 2, i + 1}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ } + break; + + case T_PTR: +- char *name = xasprintf ("ptr-%d", i); +- resolv_response_add_name (b, name); +- free (name); ++ { ++ char *name = xasprintf ("ptr-%d", i); ++ resolv_response_add_name (b, name); ++ free (name); ++ } + break; + } + resolv_response_close_record (b); diff --git a/glibc-rh2104907.patch b/glibc-rh2104907.patch new file mode 100644 index 0000000..3a65f18 --- /dev/null +++ b/glibc-rh2104907.patch @@ -0,0 +1,14 @@ +diff --git a/localedata/SUPPORTED b/localedata/SUPPORTED +index a4bf79c6a6e6401b..fdf15fddf5178319 100644 +--- a/localedata/SUPPORTED ++++ b/localedata/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/glibc-rh2109510-1.patch b/glibc-rh2109510-1.patch new file mode 100644 index 0000000..52b069e --- /dev/null +++ b/glibc-rh2109510-1.patch @@ -0,0 +1,27 @@ +commit 97f8225d22ef727ae9935cc231643efdc430d530 +Author: Zack Weinberg +Date: Thu Mar 14 09:44:22 2019 -0400 + + scripts/check-obsolete-constructs.py: Process all headers as UTF-8. + + A few of our installed headers contain UTF-8 in comments. + check-obsolete-constructs opened files without explicitly specifying + their encoding, so it would barf on these headers if “make check” was + run in a non-UTF-8 locale. + + * scripts/check-obsolete-constructs.py (HeaderChecker.check): + Specify encoding="utf-8" when opening headers to check. + +diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py +index ce5c72251f4d7cc0..89d21dea6e788783 100755 +--- a/scripts/check-obsolete-constructs.py ++++ b/scripts/check-obsolete-constructs.py +@@ -437,7 +437,7 @@ class HeaderChecker: + def check(self, fname): + self.fname = fname + try: +- with open(fname, "rt") as fp: ++ with open(fname, "rt", encoding="utf-8") as fp: + contents = fp.read() + except OSError as e: + sys.stderr.write("{}: {}\n".format(fname, e.strerror)) diff --git a/glibc-rh2109510-10.patch b/glibc-rh2109510-10.patch new file mode 100644 index 0000000..31291df --- /dev/null +++ b/glibc-rh2109510-10.patch @@ -0,0 +1,1449 @@ +commit 30035d67728a846fa39749cd162afd278ac654c4 +Author: Florian Weimer +Date: Mon Apr 11 11:28:08 2022 +0200 + + scripts: Add glibcelf.py module + + Hopefully, this will lead to tests that are easier to maintain. The + current approach of parsing readelf -W output using regular expressions + is not necessarily easier than parsing the ELF data directly. + + This module is still somewhat incomplete (e.g., coverage of relocation + types and versioning information is missing), but it is sufficient to + perform basic symbol analysis or program header analysis. + + The EM_* mapping for architecture-specific constant classes (e.g., + SttX86_64) is not yet implemented. The classes are defined for the + benefit of elf/tst-glibcelf.py. + + Reviewed-by: Siddhesh Poyarekar + +Conflicts: + elf/Makefile + (prelink removal upstream) + +diff --git a/elf/Makefile b/elf/Makefile +index 44966b9dfef15463..89ce4f5196e5eb39 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -967,6 +967,13 @@ tests-special += $(objpfx)tst-prelink-cmp.out + endif + endif + ++tests-special += $(objpfx)tst-glibcelf.out ++$(objpfx)tst-glibcelf.out: tst-glibcelf.py elf.h $(..)/scripts/glibcelf.py \ ++ $(..)/scripts/glibcextract.py ++ PYTHONPATH=$(..)scripts $(PYTHON) tst-glibcelf.py \ ++ --cc="$(CC) $(patsubst -DMODULE_NAME=%,-DMODULE_NAME=testsuite,$(CPPFLAGS))" \ ++ < /dev/null > $@ 2>&1; $(evaluate-test) ++ + # The test requires shared _and_ PIE because the executable + # unit test driver must be able to link with the shared object + # that is going to eventually go into an installed DSO. +diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py +new file mode 100644 +index 0000000000000000..bf15a3bad4479e08 +--- /dev/null ++++ b/elf/tst-glibcelf.py +@@ -0,0 +1,260 @@ ++#!/usr/bin/python3 ++# Verify scripts/glibcelf.py contents against elf/elf.h. ++# 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 ++# . ++ ++import argparse ++import enum ++import sys ++ ++import glibcelf ++import glibcextract ++ ++errors_encountered = 0 ++ ++def error(message): ++ global errors_encountered ++ sys.stdout.write('error: {}\n'.format(message)) ++ errors_encountered += 1 ++ ++# The enum constants in glibcelf are expected to have exactly these ++# prefixes. ++expected_constant_prefixes = tuple( ++ 'ELFCLASS ELFDATA EM_ ET_ DT_ PF_ PT_ SHF_ SHN_ SHT_ STB_ STT_'.split()) ++ ++def find_constant_prefix(name): ++ """Returns a matching prefix from expected_constant_prefixes or None.""" ++ for prefix in expected_constant_prefixes: ++ if name.startswith(prefix): ++ return prefix ++ return None ++ ++def find_enum_types(): ++ """A generator for OpenIntEnum and IntFlag classes in glibcelf.""" ++ for obj in vars(glibcelf).values(): ++ if isinstance(obj, type) and obj.__bases__[0] in ( ++ glibcelf._OpenIntEnum, enum.Enum, enum.IntFlag): ++ yield obj ++ ++def check_duplicates(): ++ """Verifies that enum types do not have duplicate values. ++ ++ Different types must have different member names, too. ++ ++ """ ++ global_seen = {} ++ for typ in find_enum_types(): ++ seen = {} ++ last = None ++ for (name, e) in typ.__members__.items(): ++ if e.value in seen: ++ error('{} has {}={} and {}={}'.format( ++ typ, seen[e.value], e.value, name, e.value)) ++ last = e ++ else: ++ seen[e.value] = name ++ if last is not None and last.value > e.value: ++ error('{} has {}={} after {}={}'.format( ++ typ, name, e.value, last.name, last.value)) ++ if name in global_seen: ++ error('{} used in {} and {}'.format( ++ name, global_seen[name], typ)) ++ else: ++ global_seen[name] = typ ++ ++def check_constant_prefixes(): ++ """Check that the constant prefixes match expected_constant_prefixes.""" ++ seen = set() ++ for typ in find_enum_types(): ++ typ_prefix = None ++ for val in typ: ++ prefix = find_constant_prefix(val.name) ++ if prefix is None: ++ error('constant {!r} for {} has unknown prefix'.format( ++ val, typ)) ++ break ++ elif typ_prefix is None: ++ typ_prefix = prefix ++ seen.add(typ_prefix) ++ elif prefix != typ_prefix: ++ error('prefix {!r} for constant {!r}, expected {!r}'.format( ++ prefix, val, typ_prefix)) ++ if typ_prefix is None: ++ error('empty enum type {}'.format(typ)) ++ ++ for prefix in sorted(set(expected_constant_prefixes) - seen): ++ error('missing constant prefix {!r}'.format(prefix)) ++ # Reverse difference is already covered inside the loop. ++ ++def find_elf_h_constants(cc): ++ """Returns a dictionary of relevant constants from .""" ++ return glibcextract.compute_macro_consts( ++ source_text='#include ', ++ cc=cc, ++ macro_re='|'.join( ++ prefix + '.*' for prefix in expected_constant_prefixes)) ++ ++# The first part of the pair is a name of an constant that is ++# dropped from glibcelf. The second part is the constant as it is ++# used in . ++glibcelf_skipped_aliases = ( ++ ('EM_ARC_A5', 'EM_ARC_COMPACT'), ++ ('PF_PARISC_SBP', 'PF_HP_SBP') ++) ++ ++# Constants that provide little value and are not included in ++# glibcelf: *LO*/*HI* range constants, *NUM constants counting the ++# number of constants. Also includes the alias names from ++# glibcelf_skipped_aliases. ++glibcelf_skipped_constants = frozenset( ++ [e[0] for e in glibcelf_skipped_aliases]) | frozenset(""" ++DT_AARCH64_NUM ++DT_ADDRNUM ++DT_ADDRRNGHI ++DT_ADDRRNGLO ++DT_ALPHA_NUM ++DT_ENCODING ++DT_EXTRANUM ++DT_HIOS ++DT_HIPROC ++DT_IA_64_NUM ++DT_LOOS ++DT_LOPROC ++DT_MIPS_NUM ++DT_NUM ++DT_PPC64_NUM ++DT_PPC_NUM ++DT_PROCNUM ++DT_SPARC_NUM ++DT_VALNUM ++DT_VALRNGHI ++DT_VALRNGLO ++DT_VERSIONTAGNUM ++ELFCLASSNUM ++ELFDATANUM ++ET_HIOS ++ET_HIPROC ++ET_LOOS ++ET_LOPROC ++ET_NUM ++PF_MASKOS ++PF_MASKPROC ++PT_HIOS ++PT_HIPROC ++PT_HISUNW ++PT_LOOS ++PT_LOPROC ++PT_LOSUNW ++SHF_MASKOS ++SHF_MASKPROC ++SHN_HIOS ++SHN_HIPROC ++SHN_HIRESERVE ++SHN_LOOS ++SHN_LOPROC ++SHN_LORESERVE ++SHT_HIOS ++SHT_HIPROC ++SHT_HIPROC ++SHT_HISUNW ++SHT_HIUSER ++SHT_LOOS ++SHT_LOPROC ++SHT_LOSUNW ++SHT_LOUSER ++SHT_NUM ++STB_HIOS ++STB_HIPROC ++STB_LOOS ++STB_LOPROC ++STB_NUM ++STT_HIOS ++STT_HIPROC ++STT_LOOS ++STT_LOPROC ++STT_NUM ++""".strip().split()) ++ ++def check_constant_values(cc): ++ """Checks the values of constants against glibcelf.""" ++ ++ glibcelf_constants = { ++ e.name: e for typ in find_enum_types() for e in typ} ++ elf_h_constants = find_elf_h_constants(cc=cc) ++ ++ missing_in_glibcelf = (set(elf_h_constants) - set(glibcelf_constants) ++ - glibcelf_skipped_constants) ++ for name in sorted(missing_in_glibcelf): ++ error('constant {} is missing from glibcelf'.format(name)) ++ ++ unexpected_in_glibcelf = \ ++ set(glibcelf_constants) & glibcelf_skipped_constants ++ for name in sorted(unexpected_in_glibcelf): ++ error('constant {} is supposed to be filtered from glibcelf'.format( ++ name)) ++ ++ missing_in_elf_h = set(glibcelf_constants) - set(elf_h_constants) ++ for name in sorted(missing_in_elf_h): ++ error('constant {} is missing from '.format(name)) ++ ++ expected_in_elf_h = glibcelf_skipped_constants - set(elf_h_constants) ++ for name in expected_in_elf_h: ++ error('filtered constant {} is missing from '.format(name)) ++ ++ for alias_name, name_in_glibcelf in glibcelf_skipped_aliases: ++ if name_in_glibcelf not in glibcelf_constants: ++ error('alias value {} for {} not in glibcelf'.format( ++ name_in_glibcelf, alias_name)) ++ elif (int(elf_h_constants[alias_name]) ++ != glibcelf_constants[name_in_glibcelf].value): ++ error(' has {}={}, glibcelf has {}={}'.format( ++ alias_name, elf_h_constants[alias_name], ++ name_in_glibcelf, glibcelf_constants[name_in_glibcelf])) ++ ++ # Check for value mismatches: ++ for name in sorted(set(glibcelf_constants) & set(elf_h_constants)): ++ glibcelf_value = glibcelf_constants[name].value ++ elf_h_value = int(elf_h_constants[name]) ++ # On 32-bit architectures as some constants that are ++ # parsed as signed, while they are unsigned in glibcelf. So ++ # far, this only affects some flag constants, so special-case ++ # them here. ++ if (glibcelf_value != elf_h_value ++ and not (isinstance(glibcelf_constants[name], enum.IntFlag) ++ and glibcelf_value == 1 << 31 ++ and elf_h_value == -(1 << 31))): ++ error('{}: glibcelf has {!r}, has {!r}'.format( ++ name, glibcelf_value, elf_h_value)) ++ ++def main(): ++ """The main entry point.""" ++ parser = argparse.ArgumentParser( ++ description="Check glibcelf.py and elf.h against each other.") ++ parser.add_argument('--cc', metavar='CC', ++ help='C compiler (including options) to use') ++ args = parser.parse_args() ++ ++ check_duplicates() ++ check_constant_prefixes() ++ check_constant_values(cc=args.cc) ++ ++ if errors_encountered > 0: ++ print("note: errors encountered:", errors_encountered) ++ sys.exit(1) ++ ++if __name__ == '__main__': ++ main() +diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py +new file mode 100644 +index 0000000000000000..8f7d0ca184845714 +--- /dev/null ++++ b/scripts/glibcelf.py +@@ -0,0 +1,1135 @@ ++#!/usr/bin/python3 ++# ELF support functionality for Python. ++# 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 ++# . ++ ++"""Basic ELF parser. ++ ++Use Image.readfile(path) to read an ELF file into memory and begin ++parsing it. ++ ++""" ++ ++import collections ++import enum ++import struct ++ ++class _OpenIntEnum(enum.IntEnum): ++ """Integer enumeration that supports arbitrary int values.""" ++ @classmethod ++ def _missing_(cls, value): ++ # See enum.IntFlag._create_pseudo_member_. This allows ++ # creating of enum constants with arbitrary integer values. ++ pseudo_member = int.__new__(cls, value) ++ pseudo_member._name_ = None ++ pseudo_member._value_ = value ++ return pseudo_member ++ ++ def __repr__(self): ++ name = self._name_ ++ if name is not None: ++ # The names have prefixes like SHT_, implying their type. ++ return name ++ return '{}({})'.format(self.__class__.__name__, self._value_) ++ ++ def __str__(self): ++ name = self._name_ ++ if name is not None: ++ return name ++ return str(self._value_) ++ ++class ElfClass(_OpenIntEnum): ++ """ELF word size. Type of EI_CLASS values.""" ++ ELFCLASSNONE = 0 ++ ELFCLASS32 = 1 ++ ELFCLASS64 = 2 ++ ++class ElfData(_OpenIntEnum): ++ """ELF endianess. Type of EI_DATA values.""" ++ ELFDATANONE = 0 ++ ELFDATA2LSB = 1 ++ ELFDATA2MSB = 2 ++ ++class Machine(_OpenIntEnum): ++ """ELF machine type. Type of values in Ehdr.e_machine field.""" ++ EM_NONE = 0 ++ EM_M32 = 1 ++ EM_SPARC = 2 ++ EM_386 = 3 ++ EM_68K = 4 ++ EM_88K = 5 ++ EM_IAMCU = 6 ++ EM_860 = 7 ++ EM_MIPS = 8 ++ EM_S370 = 9 ++ EM_MIPS_RS3_LE = 10 ++ EM_PARISC = 15 ++ EM_VPP500 = 17 ++ EM_SPARC32PLUS = 18 ++ EM_960 = 19 ++ EM_PPC = 20 ++ EM_PPC64 = 21 ++ EM_S390 = 22 ++ EM_SPU = 23 ++ EM_V800 = 36 ++ EM_FR20 = 37 ++ EM_RH32 = 38 ++ EM_RCE = 39 ++ EM_ARM = 40 ++ EM_FAKE_ALPHA = 41 ++ EM_SH = 42 ++ EM_SPARCV9 = 43 ++ EM_TRICORE = 44 ++ EM_ARC = 45 ++ EM_H8_300 = 46 ++ EM_H8_300H = 47 ++ EM_H8S = 48 ++ EM_H8_500 = 49 ++ EM_IA_64 = 50 ++ EM_MIPS_X = 51 ++ EM_COLDFIRE = 52 ++ EM_68HC12 = 53 ++ EM_MMA = 54 ++ EM_PCP = 55 ++ EM_NCPU = 56 ++ EM_NDR1 = 57 ++ EM_STARCORE = 58 ++ EM_ME16 = 59 ++ EM_ST100 = 60 ++ EM_TINYJ = 61 ++ EM_X86_64 = 62 ++ EM_PDSP = 63 ++ EM_PDP10 = 64 ++ EM_PDP11 = 65 ++ EM_FX66 = 66 ++ EM_ST9PLUS = 67 ++ EM_ST7 = 68 ++ EM_68HC16 = 69 ++ EM_68HC11 = 70 ++ EM_68HC08 = 71 ++ EM_68HC05 = 72 ++ EM_SVX = 73 ++ EM_ST19 = 74 ++ EM_VAX = 75 ++ EM_CRIS = 76 ++ EM_JAVELIN = 77 ++ EM_FIREPATH = 78 ++ EM_ZSP = 79 ++ EM_MMIX = 80 ++ EM_HUANY = 81 ++ EM_PRISM = 82 ++ EM_AVR = 83 ++ EM_FR30 = 84 ++ EM_D10V = 85 ++ EM_D30V = 86 ++ EM_V850 = 87 ++ EM_M32R = 88 ++ EM_MN10300 = 89 ++ EM_MN10200 = 90 ++ EM_PJ = 91 ++ EM_OPENRISC = 92 ++ EM_ARC_COMPACT = 93 ++ EM_XTENSA = 94 ++ EM_VIDEOCORE = 95 ++ EM_TMM_GPP = 96 ++ EM_NS32K = 97 ++ EM_TPC = 98 ++ EM_SNP1K = 99 ++ EM_ST200 = 100 ++ EM_IP2K = 101 ++ EM_MAX = 102 ++ EM_CR = 103 ++ EM_F2MC16 = 104 ++ EM_MSP430 = 105 ++ EM_BLACKFIN = 106 ++ EM_SE_C33 = 107 ++ EM_SEP = 108 ++ EM_ARCA = 109 ++ EM_UNICORE = 110 ++ EM_EXCESS = 111 ++ EM_DXP = 112 ++ EM_ALTERA_NIOS2 = 113 ++ EM_CRX = 114 ++ EM_XGATE = 115 ++ EM_C166 = 116 ++ EM_M16C = 117 ++ EM_DSPIC30F = 118 ++ EM_CE = 119 ++ EM_M32C = 120 ++ EM_TSK3000 = 131 ++ EM_RS08 = 132 ++ EM_SHARC = 133 ++ EM_ECOG2 = 134 ++ EM_SCORE7 = 135 ++ EM_DSP24 = 136 ++ EM_VIDEOCORE3 = 137 ++ EM_LATTICEMICO32 = 138 ++ EM_SE_C17 = 139 ++ EM_TI_C6000 = 140 ++ EM_TI_C2000 = 141 ++ EM_TI_C5500 = 142 ++ EM_TI_ARP32 = 143 ++ EM_TI_PRU = 144 ++ EM_MMDSP_PLUS = 160 ++ EM_CYPRESS_M8C = 161 ++ EM_R32C = 162 ++ EM_TRIMEDIA = 163 ++ EM_QDSP6 = 164 ++ EM_8051 = 165 ++ EM_STXP7X = 166 ++ EM_NDS32 = 167 ++ EM_ECOG1X = 168 ++ EM_MAXQ30 = 169 ++ EM_XIMO16 = 170 ++ EM_MANIK = 171 ++ EM_CRAYNV2 = 172 ++ EM_RX = 173 ++ EM_METAG = 174 ++ EM_MCST_ELBRUS = 175 ++ EM_ECOG16 = 176 ++ EM_CR16 = 177 ++ EM_ETPU = 178 ++ EM_SLE9X = 179 ++ EM_L10M = 180 ++ EM_K10M = 181 ++ EM_AARCH64 = 183 ++ EM_AVR32 = 185 ++ EM_STM8 = 186 ++ EM_TILE64 = 187 ++ EM_TILEPRO = 188 ++ EM_MICROBLAZE = 189 ++ EM_CUDA = 190 ++ EM_TILEGX = 191 ++ EM_CLOUDSHIELD = 192 ++ EM_COREA_1ST = 193 ++ EM_COREA_2ND = 194 ++ EM_ARCV2 = 195 ++ EM_OPEN8 = 196 ++ EM_RL78 = 197 ++ EM_VIDEOCORE5 = 198 ++ EM_78KOR = 199 ++ EM_56800EX = 200 ++ EM_BA1 = 201 ++ EM_BA2 = 202 ++ EM_XCORE = 203 ++ EM_MCHP_PIC = 204 ++ EM_INTELGT = 205 ++ EM_KM32 = 210 ++ EM_KMX32 = 211 ++ EM_EMX16 = 212 ++ EM_EMX8 = 213 ++ EM_KVARC = 214 ++ EM_CDP = 215 ++ EM_COGE = 216 ++ EM_COOL = 217 ++ EM_NORC = 218 ++ EM_CSR_KALIMBA = 219 ++ EM_Z80 = 220 ++ EM_VISIUM = 221 ++ EM_FT32 = 222 ++ EM_MOXIE = 223 ++ EM_AMDGPU = 224 ++ EM_RISCV = 243 ++ EM_BPF = 247 ++ EM_CSKY = 252 ++ EM_NUM = 253 ++ EM_ALPHA = 0x9026 ++ ++class Et(_OpenIntEnum): ++ """ELF file type. Type of ET_* values and the Ehdr.e_type field.""" ++ ET_NONE = 0 ++ ET_REL = 1 ++ ET_EXEC = 2 ++ ET_DYN = 3 ++ ET_CORE = 4 ++ ++class Shn(_OpenIntEnum): ++ """ELF reserved section indices.""" ++ SHN_UNDEF = 0 ++ SHN_BEFORE = 0xff00 ++ SHN_AFTER = 0xff01 ++ SHN_ABS = 0xfff1 ++ SHN_COMMON = 0xfff2 ++ SHN_XINDEX = 0xffff ++ ++class ShnMIPS(enum.Enum): ++ """Supplemental SHN_* constants for EM_MIPS.""" ++ SHN_MIPS_ACOMMON = 0xff00 ++ SHN_MIPS_TEXT = 0xff01 ++ SHN_MIPS_DATA = 0xff02 ++ SHN_MIPS_SCOMMON = 0xff03 ++ SHN_MIPS_SUNDEFINED = 0xff04 ++ ++class ShnPARISC(enum.Enum): ++ """Supplemental SHN_* constants for EM_PARISC.""" ++ SHN_PARISC_ANSI_COMMON = 0xff00 ++ SHN_PARISC_HUGE_COMMON = 0xff01 ++ ++class Sht(_OpenIntEnum): ++ """ELF section types. Type of SHT_* values.""" ++ SHT_NULL = 0 ++ SHT_PROGBITS = 1 ++ SHT_SYMTAB = 2 ++ SHT_STRTAB = 3 ++ SHT_RELA = 4 ++ SHT_HASH = 5 ++ SHT_DYNAMIC = 6 ++ SHT_NOTE = 7 ++ SHT_NOBITS = 8 ++ SHT_REL = 9 ++ SHT_SHLIB = 10 ++ SHT_DYNSYM = 11 ++ SHT_INIT_ARRAY = 14 ++ SHT_FINI_ARRAY = 15 ++ SHT_PREINIT_ARRAY = 16 ++ SHT_GROUP = 17 ++ SHT_SYMTAB_SHNDX = 18 ++ SHT_GNU_ATTRIBUTES = 0x6ffffff5 ++ SHT_GNU_HASH = 0x6ffffff6 ++ SHT_GNU_LIBLIST = 0x6ffffff7 ++ SHT_CHECKSUM = 0x6ffffff8 ++ SHT_SUNW_move = 0x6ffffffa ++ SHT_SUNW_COMDAT = 0x6ffffffb ++ SHT_SUNW_syminfo = 0x6ffffffc ++ SHT_GNU_verdef = 0x6ffffffd ++ SHT_GNU_verneed = 0x6ffffffe ++ SHT_GNU_versym = 0x6fffffff ++ ++class ShtALPHA(enum.Enum): ++ """Supplemental SHT_* constants for EM_ALPHA.""" ++ SHT_ALPHA_DEBUG = 0x70000001 ++ SHT_ALPHA_REGINFO = 0x70000002 ++ ++class ShtARM(enum.Enum): ++ """Supplemental SHT_* constants for EM_ARM.""" ++ SHT_ARM_EXIDX = 0x70000001 ++ SHT_ARM_PREEMPTMAP = 0x70000002 ++ SHT_ARM_ATTRIBUTES = 0x70000003 ++ ++class ShtCSKY(enum.Enum): ++ """Supplemental SHT_* constants for EM_CSKY.""" ++ SHT_CSKY_ATTRIBUTES = 0x70000001 ++ ++class ShtIA_64(enum.Enum): ++ """Supplemental SHT_* constants for EM_IA_64.""" ++ SHT_IA_64_EXT = 0x70000000 ++ SHT_IA_64_UNWIND = 0x70000001 ++ ++class ShtMIPS(enum.Enum): ++ """Supplemental SHT_* constants for EM_MIPS.""" ++ SHT_MIPS_LIBLIST = 0x70000000 ++ SHT_MIPS_MSYM = 0x70000001 ++ SHT_MIPS_CONFLICT = 0x70000002 ++ SHT_MIPS_GPTAB = 0x70000003 ++ SHT_MIPS_UCODE = 0x70000004 ++ SHT_MIPS_DEBUG = 0x70000005 ++ SHT_MIPS_REGINFO = 0x70000006 ++ SHT_MIPS_PACKAGE = 0x70000007 ++ SHT_MIPS_PACKSYM = 0x70000008 ++ SHT_MIPS_RELD = 0x70000009 ++ SHT_MIPS_IFACE = 0x7000000b ++ SHT_MIPS_CONTENT = 0x7000000c ++ SHT_MIPS_OPTIONS = 0x7000000d ++ SHT_MIPS_SHDR = 0x70000010 ++ SHT_MIPS_FDESC = 0x70000011 ++ SHT_MIPS_EXTSYM = 0x70000012 ++ SHT_MIPS_DENSE = 0x70000013 ++ SHT_MIPS_PDESC = 0x70000014 ++ SHT_MIPS_LOCSYM = 0x70000015 ++ SHT_MIPS_AUXSYM = 0x70000016 ++ SHT_MIPS_OPTSYM = 0x70000017 ++ SHT_MIPS_LOCSTR = 0x70000018 ++ SHT_MIPS_LINE = 0x70000019 ++ SHT_MIPS_RFDESC = 0x7000001a ++ SHT_MIPS_DELTASYM = 0x7000001b ++ SHT_MIPS_DELTAINST = 0x7000001c ++ SHT_MIPS_DELTACLASS = 0x7000001d ++ SHT_MIPS_DWARF = 0x7000001e ++ SHT_MIPS_DELTADECL = 0x7000001f ++ SHT_MIPS_SYMBOL_LIB = 0x70000020 ++ SHT_MIPS_EVENTS = 0x70000021 ++ SHT_MIPS_TRANSLATE = 0x70000022 ++ SHT_MIPS_PIXIE = 0x70000023 ++ SHT_MIPS_XLATE = 0x70000024 ++ SHT_MIPS_XLATE_DEBUG = 0x70000025 ++ SHT_MIPS_WHIRL = 0x70000026 ++ SHT_MIPS_EH_REGION = 0x70000027 ++ SHT_MIPS_XLATE_OLD = 0x70000028 ++ SHT_MIPS_PDR_EXCEPTION = 0x70000029 ++ SHT_MIPS_XHASH = 0x7000002b ++ ++class ShtPARISC(enum.Enum): ++ """Supplemental SHT_* constants for EM_PARISC.""" ++ SHT_PARISC_EXT = 0x70000000 ++ SHT_PARISC_UNWIND = 0x70000001 ++ SHT_PARISC_DOC = 0x70000002 ++ ++class Pf(enum.IntFlag): ++ """Program header flags. Type of Phdr.p_flags values.""" ++ PF_X = 1 ++ PF_W = 2 ++ PF_R = 4 ++ ++class PfARM(enum.IntFlag): ++ """Supplemental PF_* flags for EM_ARM.""" ++ PF_ARM_SB = 0x10000000 ++ PF_ARM_PI = 0x20000000 ++ PF_ARM_ABS = 0x40000000 ++ ++class PfPARISC(enum.IntFlag): ++ """Supplemental PF_* flags for EM_PARISC.""" ++ PF_HP_PAGE_SIZE = 0x00100000 ++ PF_HP_FAR_SHARED = 0x00200000 ++ PF_HP_NEAR_SHARED = 0x00400000 ++ PF_HP_CODE = 0x01000000 ++ PF_HP_MODIFY = 0x02000000 ++ PF_HP_LAZYSWAP = 0x04000000 ++ PF_HP_SBP = 0x08000000 ++ ++class PfIA_64(enum.IntFlag): ++ """Supplemental PF_* flags for EM_IA_64.""" ++ PF_IA_64_NORECOV = 0x80000000 ++ ++class PfMIPS(enum.IntFlag): ++ """Supplemental PF_* flags for EM_MIPS.""" ++ PF_MIPS_LOCAL = 0x10000000 ++ ++class Shf(enum.IntFlag): ++ """Section flags. Type of Shdr.sh_type values.""" ++ SHF_WRITE = 1 << 0 ++ SHF_ALLOC = 1 << 1 ++ SHF_EXECINSTR = 1 << 2 ++ SHF_MERGE = 1 << 4 ++ SHF_STRINGS = 1 << 5 ++ SHF_INFO_LINK = 1 << 6 ++ SHF_LINK_ORDER = 1 << 7 ++ SHF_OS_NONCONFORMING = 256 ++ SHF_GROUP = 1 << 9 ++ SHF_TLS = 1 << 10 ++ SHF_COMPRESSED = 1 << 11 ++ SHF_GNU_RETAIN = 1 << 21 ++ SHF_ORDERED = 1 << 30 ++ SHF_EXCLUDE = 1 << 31 ++ ++class ShfALPHA(enum.IntFlag): ++ """Supplemental SHF_* constants for EM_ALPHA.""" ++ SHF_ALPHA_GPREL = 0x10000000 ++ ++class ShfARM(enum.IntFlag): ++ """Supplemental SHF_* constants for EM_ARM.""" ++ SHF_ARM_ENTRYSECT = 0x10000000 ++ SHF_ARM_COMDEF = 0x80000000 ++ ++class ShfIA_64(enum.IntFlag): ++ """Supplemental SHF_* constants for EM_IA_64.""" ++ SHF_IA_64_SHORT = 0x10000000 ++ SHF_IA_64_NORECOV = 0x20000000 ++ ++class ShfMIPS(enum.IntFlag): ++ """Supplemental SHF_* constants for EM_MIPS.""" ++ SHF_MIPS_GPREL = 0x10000000 ++ SHF_MIPS_MERGE = 0x20000000 ++ SHF_MIPS_ADDR = 0x40000000 ++ SHF_MIPS_STRINGS = 0x80000000 ++ SHF_MIPS_NOSTRIP = 0x08000000 ++ SHF_MIPS_LOCAL = 0x04000000 ++ SHF_MIPS_NAMES = 0x02000000 ++ SHF_MIPS_NODUPE = 0x01000000 ++ ++class ShfPARISC(enum.IntFlag): ++ """Supplemental SHF_* constants for EM_PARISC.""" ++ SHF_PARISC_SHORT = 0x20000000 ++ SHF_PARISC_HUGE = 0x40000000 ++ SHF_PARISC_SBP = 0x80000000 ++ ++class Stb(_OpenIntEnum): ++ """ELF symbol binding type.""" ++ STB_LOCAL = 0 ++ STB_GLOBAL = 1 ++ STB_WEAK = 2 ++ STB_GNU_UNIQUE = 10 ++ STB_MIPS_SPLIT_COMMON = 13 ++ ++class Stt(_OpenIntEnum): ++ """ELF symbol type.""" ++ STT_NOTYPE = 0 ++ STT_OBJECT = 1 ++ STT_FUNC = 2 ++ STT_SECTION = 3 ++ STT_FILE = 4 ++ STT_COMMON = 5 ++ STT_TLS = 6 ++ STT_GNU_IFUNC = 10 ++ ++class SttARM(enum.Enum): ++ """Supplemental STT_* constants for EM_ARM.""" ++ STT_ARM_TFUNC = 13 ++ STT_ARM_16BIT = 15 ++ ++class SttPARISC(enum.Enum): ++ """Supplemental STT_* constants for EM_PARISC.""" ++ STT_HP_OPAQUE = 11 ++ STT_HP_STUB = 12 ++ STT_PARISC_MILLICODE = 13 ++ ++class SttSPARC(enum.Enum): ++ """Supplemental STT_* constants for EM_SPARC.""" ++ STT_SPARC_REGISTER = 13 ++ ++class SttX86_64(enum.Enum): ++ """Supplemental STT_* constants for EM_X86_64.""" ++ SHT_X86_64_UNWIND = 0x70000001 ++ ++class Pt(_OpenIntEnum): ++ """ELF program header types. Type of Phdr.p_type.""" ++ PT_NULL = 0 ++ PT_LOAD = 1 ++ PT_DYNAMIC = 2 ++ PT_INTERP = 3 ++ PT_NOTE = 4 ++ PT_SHLIB = 5 ++ PT_PHDR = 6 ++ PT_TLS = 7 ++ PT_NUM = 8 ++ PT_GNU_EH_FRAME = 0x6474e550 ++ PT_GNU_STACK = 0x6474e551 ++ PT_GNU_RELRO = 0x6474e552 ++ PT_GNU_PROPERTY = 0x6474e553 ++ PT_SUNWBSS = 0x6ffffffa ++ PT_SUNWSTACK = 0x6ffffffb ++ ++class PtARM(enum.Enum): ++ """Supplemental PT_* constants for EM_ARM.""" ++ PT_ARM_EXIDX = 0x70000001 ++ ++class PtIA_64(enum.Enum): ++ """Supplemental PT_* constants for EM_IA_64.""" ++ PT_IA_64_HP_OPT_ANOT = 0x60000012 ++ PT_IA_64_HP_HSL_ANOT = 0x60000013 ++ PT_IA_64_HP_STACK = 0x60000014 ++ PT_IA_64_ARCHEXT = 0x70000000 ++ PT_IA_64_UNWIND = 0x70000001 ++ ++class PtMIPS(enum.Enum): ++ """Supplemental PT_* constants for EM_MIPS.""" ++ PT_MIPS_REGINFO = 0x70000000 ++ PT_MIPS_RTPROC = 0x70000001 ++ PT_MIPS_OPTIONS = 0x70000002 ++ PT_MIPS_ABIFLAGS = 0x70000003 ++ ++class PtPARISC(enum.Enum): ++ """Supplemental PT_* constants for EM_PARISC.""" ++ PT_HP_TLS = 0x60000000 ++ PT_HP_CORE_NONE = 0x60000001 ++ PT_HP_CORE_VERSION = 0x60000002 ++ PT_HP_CORE_KERNEL = 0x60000003 ++ PT_HP_CORE_COMM = 0x60000004 ++ PT_HP_CORE_PROC = 0x60000005 ++ PT_HP_CORE_LOADABLE = 0x60000006 ++ PT_HP_CORE_STACK = 0x60000007 ++ PT_HP_CORE_SHM = 0x60000008 ++ PT_HP_CORE_MMF = 0x60000009 ++ PT_HP_PARALLEL = 0x60000010 ++ PT_HP_FASTBIND = 0x60000011 ++ PT_HP_OPT_ANNOT = 0x60000012 ++ PT_HP_HSL_ANNOT = 0x60000013 ++ PT_HP_STACK = 0x60000014 ++ PT_PARISC_ARCHEXT = 0x70000000 ++ PT_PARISC_UNWIND = 0x70000001 ++ ++class Dt(_OpenIntEnum): ++ """ELF dynamic segment tags. Type of Dyn.d_val.""" ++ DT_NULL = 0 ++ DT_NEEDED = 1 ++ DT_PLTRELSZ = 2 ++ DT_PLTGOT = 3 ++ DT_HASH = 4 ++ DT_STRTAB = 5 ++ DT_SYMTAB = 6 ++ DT_RELA = 7 ++ DT_RELASZ = 8 ++ DT_RELAENT = 9 ++ DT_STRSZ = 10 ++ DT_SYMENT = 11 ++ DT_INIT = 12 ++ DT_FINI = 13 ++ DT_SONAME = 14 ++ DT_RPATH = 15 ++ DT_SYMBOLIC = 16 ++ DT_REL = 17 ++ DT_RELSZ = 18 ++ DT_RELENT = 19 ++ DT_PLTREL = 20 ++ DT_DEBUG = 21 ++ DT_TEXTREL = 22 ++ DT_JMPREL = 23 ++ DT_BIND_NOW = 24 ++ DT_INIT_ARRAY = 25 ++ DT_FINI_ARRAY = 26 ++ DT_INIT_ARRAYSZ = 27 ++ DT_FINI_ARRAYSZ = 28 ++ DT_RUNPATH = 29 ++ DT_FLAGS = 30 ++ DT_PREINIT_ARRAY = 32 ++ DT_PREINIT_ARRAYSZ = 33 ++ DT_SYMTAB_SHNDX = 34 ++ DT_GNU_PRELINKED = 0x6ffffdf5 ++ DT_GNU_CONFLICTSZ = 0x6ffffdf6 ++ DT_GNU_LIBLISTSZ = 0x6ffffdf7 ++ DT_CHECKSUM = 0x6ffffdf8 ++ DT_PLTPADSZ = 0x6ffffdf9 ++ DT_MOVEENT = 0x6ffffdfa ++ DT_MOVESZ = 0x6ffffdfb ++ DT_FEATURE_1 = 0x6ffffdfc ++ DT_POSFLAG_1 = 0x6ffffdfd ++ DT_SYMINSZ = 0x6ffffdfe ++ DT_SYMINENT = 0x6ffffdff ++ DT_GNU_HASH = 0x6ffffef5 ++ DT_TLSDESC_PLT = 0x6ffffef6 ++ DT_TLSDESC_GOT = 0x6ffffef7 ++ DT_GNU_CONFLICT = 0x6ffffef8 ++ DT_GNU_LIBLIST = 0x6ffffef9 ++ DT_CONFIG = 0x6ffffefa ++ DT_DEPAUDIT = 0x6ffffefb ++ DT_AUDIT = 0x6ffffefc ++ DT_PLTPAD = 0x6ffffefd ++ DT_MOVETAB = 0x6ffffefe ++ DT_SYMINFO = 0x6ffffeff ++ DT_VERSYM = 0x6ffffff0 ++ DT_RELACOUNT = 0x6ffffff9 ++ DT_RELCOUNT = 0x6ffffffa ++ DT_FLAGS_1 = 0x6ffffffb ++ DT_VERDEF = 0x6ffffffc ++ DT_VERDEFNUM = 0x6ffffffd ++ DT_VERNEED = 0x6ffffffe ++ DT_VERNEEDNUM = 0x6fffffff ++ DT_AUXILIARY = 0x7ffffffd ++ DT_FILTER = 0x7fffffff ++ ++class DtAARCH64(enum.Enum): ++ """Supplemental DT_* constants for EM_AARCH64.""" ++ DT_AARCH64_BTI_PLT = 0x70000001 ++ DT_AARCH64_PAC_PLT = 0x70000003 ++ DT_AARCH64_VARIANT_PCS = 0x70000005 ++ ++class DtALPHA(enum.Enum): ++ """Supplemental DT_* constants for EM_ALPHA.""" ++ DT_ALPHA_PLTRO = 0x70000000 ++ ++class DtALTERA_NIOS2(enum.Enum): ++ """Supplemental DT_* constants for EM_ALTERA_NIOS2.""" ++ DT_NIOS2_GP = 0x70000002 ++ ++class DtIA_64(enum.Enum): ++ """Supplemental DT_* constants for EM_IA_64.""" ++ DT_IA_64_PLT_RESERVE = 0x70000000 ++ ++class DtMIPS(enum.Enum): ++ """Supplemental DT_* constants for EM_MIPS.""" ++ DT_MIPS_RLD_VERSION = 0x70000001 ++ DT_MIPS_TIME_STAMP = 0x70000002 ++ DT_MIPS_ICHECKSUM = 0x70000003 ++ DT_MIPS_IVERSION = 0x70000004 ++ DT_MIPS_FLAGS = 0x70000005 ++ DT_MIPS_BASE_ADDRESS = 0x70000006 ++ DT_MIPS_MSYM = 0x70000007 ++ DT_MIPS_CONFLICT = 0x70000008 ++ DT_MIPS_LIBLIST = 0x70000009 ++ DT_MIPS_LOCAL_GOTNO = 0x7000000a ++ DT_MIPS_CONFLICTNO = 0x7000000b ++ DT_MIPS_LIBLISTNO = 0x70000010 ++ DT_MIPS_SYMTABNO = 0x70000011 ++ DT_MIPS_UNREFEXTNO = 0x70000012 ++ DT_MIPS_GOTSYM = 0x70000013 ++ DT_MIPS_HIPAGENO = 0x70000014 ++ DT_MIPS_RLD_MAP = 0x70000016 ++ DT_MIPS_DELTA_CLASS = 0x70000017 ++ DT_MIPS_DELTA_CLASS_NO = 0x70000018 ++ DT_MIPS_DELTA_INSTANCE = 0x70000019 ++ DT_MIPS_DELTA_INSTANCE_NO = 0x7000001a ++ DT_MIPS_DELTA_RELOC = 0x7000001b ++ DT_MIPS_DELTA_RELOC_NO = 0x7000001c ++ DT_MIPS_DELTA_SYM = 0x7000001d ++ DT_MIPS_DELTA_SYM_NO = 0x7000001e ++ DT_MIPS_DELTA_CLASSSYM = 0x70000020 ++ DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021 ++ DT_MIPS_CXX_FLAGS = 0x70000022 ++ DT_MIPS_PIXIE_INIT = 0x70000023 ++ DT_MIPS_SYMBOL_LIB = 0x70000024 ++ DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025 ++ DT_MIPS_LOCAL_GOTIDX = 0x70000026 ++ DT_MIPS_HIDDEN_GOTIDX = 0x70000027 ++ DT_MIPS_PROTECTED_GOTIDX = 0x70000028 ++ DT_MIPS_OPTIONS = 0x70000029 ++ DT_MIPS_INTERFACE = 0x7000002a ++ DT_MIPS_DYNSTR_ALIGN = 0x7000002b ++ DT_MIPS_INTERFACE_SIZE = 0x7000002c ++ DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002d ++ DT_MIPS_PERF_SUFFIX = 0x7000002e ++ DT_MIPS_COMPACT_SIZE = 0x7000002f ++ DT_MIPS_GP_VALUE = 0x70000030 ++ DT_MIPS_AUX_DYNAMIC = 0x70000031 ++ DT_MIPS_PLTGOT = 0x70000032 ++ DT_MIPS_RWPLT = 0x70000034 ++ DT_MIPS_RLD_MAP_REL = 0x70000035 ++ DT_MIPS_XHASH = 0x70000036 ++ ++class DtPPC(enum.Enum): ++ """Supplemental DT_* constants for EM_PPC.""" ++ DT_PPC_GOT = 0x70000000 ++ DT_PPC_OPT = 0x70000001 ++ ++class DtPPC64(enum.Enum): ++ """Supplemental DT_* constants for EM_PPC64.""" ++ DT_PPC64_GLINK = 0x70000000 ++ DT_PPC64_OPD = 0x70000001 ++ DT_PPC64_OPDSZ = 0x70000002 ++ DT_PPC64_OPT = 0x70000003 ++ ++class DtSPARC(enum.Enum): ++ """Supplemental DT_* constants for EM_SPARC.""" ++ DT_SPARC_REGISTER = 0x70000001 ++ ++class StInfo: ++ """ELF symbol binding and type. Type of the Sym.st_info field.""" ++ def __init__(self, arg0, arg1=None): ++ if isinstance(arg0, int) and arg1 is None: ++ self.bind = Stb(arg0 >> 4) ++ self.type = Stt(arg0 & 15) ++ else: ++ self.bind = Stb(arg0) ++ self.type = Stt(arg1) ++ ++ def value(self): ++ """Returns the raw value for the bind/type combination.""" ++ return (self.bind.value() << 4) | (self.type.value()) ++ ++# Type in an ELF file. Used for deserialization. ++_Layout = collections.namedtuple('_Layout', 'unpack size') ++ ++def _define_layouts(baseclass: type, layout32: str, layout64: str, ++ types=None, fields32=None): ++ """Assign variants dict to baseclass. ++ ++ The variants dict is indexed by (ElfClass, ElfData) pairs, and its ++ values are _Layout instances. ++ ++ """ ++ struct32 = struct.Struct(layout32) ++ struct64 = struct.Struct(layout64) ++ ++ # Check that the struct formats yield the right number of components. ++ for s in (struct32, struct64): ++ example = s.unpack(b' ' * s.size) ++ if len(example) != len(baseclass._fields): ++ raise ValueError('{!r} yields wrong field count: {} != {}'.format( ++ s.format, len(example), len(baseclass._fields))) ++ ++ # Check that field names in types are correct. ++ if types is None: ++ types = () ++ for n in types: ++ if n not in baseclass._fields: ++ raise ValueError('{} does not have field {!r}'.format( ++ baseclass.__name__, n)) ++ ++ if fields32 is not None \ ++ and set(fields32) != set(baseclass._fields): ++ raise ValueError('{!r} is not a permutation of the fields {!r}'.format( ++ fields32, baseclass._fields)) ++ ++ def unique_name(name, used_names = (set((baseclass.__name__,)) ++ | set(baseclass._fields) ++ | {n.__name__ ++ for n in (types or {}).values()})): ++ """Find a name that is not used for a class or field name.""" ++ candidate = name ++ n = 0 ++ while candidate in used_names: ++ n += 1 ++ candidate = '{}{}'.format(name, n) ++ used_names.add(candidate) ++ return candidate ++ ++ blob_name = unique_name('blob') ++ struct_unpack_name = unique_name('struct_unpack') ++ comps_name = unique_name('comps') ++ ++ layouts = {} ++ for (bits, elfclass, layout, fields) in ( ++ (32, ElfClass.ELFCLASS32, layout32, fields32), ++ (64, ElfClass.ELFCLASS64, layout64, None), ++ ): ++ for (elfdata, structprefix, funcsuffix) in ( ++ (ElfData.ELFDATA2LSB, '<', 'LE'), ++ (ElfData.ELFDATA2MSB, '>', 'BE'), ++ ): ++ env = { ++ baseclass.__name__: baseclass, ++ struct_unpack_name: struct.unpack, ++ } ++ ++ # Add the type converters. ++ if types: ++ for cls in types.values(): ++ env[cls.__name__] = cls ++ ++ funcname = ''.join( ++ ('unpack_', baseclass.__name__, str(bits), funcsuffix)) ++ ++ code = ''' ++def {funcname}({blob_name}): ++'''.format(funcname=funcname, blob_name=blob_name) ++ ++ indent = ' ' * 4 ++ unpack_call = '{}({!r}, {})'.format( ++ struct_unpack_name, structprefix + layout, blob_name) ++ field_names = ', '.join(baseclass._fields) ++ if types is None and fields is None: ++ code += '{}return {}({})\n'.format( ++ indent, baseclass.__name__, unpack_call) ++ else: ++ # Destructuring tuple assignment. ++ if fields is None: ++ code += '{}{} = {}\n'.format( ++ indent, field_names, unpack_call) ++ else: ++ # Use custom field order. ++ code += '{}{} = {}\n'.format( ++ indent, ', '.join(fields), unpack_call) ++ ++ # Perform the type conversions. ++ for n in baseclass._fields: ++ if n in types: ++ code += '{}{} = {}({})\n'.format( ++ indent, n, types[n].__name__, n) ++ # Create the named tuple. ++ code += '{}return {}({})\n'.format( ++ indent, baseclass.__name__, field_names) ++ ++ exec(code, env) ++ layouts[(elfclass, elfdata)] = _Layout( ++ env[funcname], struct.calcsize(layout)) ++ baseclass.layouts = layouts ++ ++ ++# Corresponds to EI_* indices into Elf*_Ehdr.e_indent. ++class Ident(collections.namedtuple('Ident', ++ 'ei_mag ei_class ei_data ei_version ei_osabi ei_abiversion ei_pad')): ++ ++ def __new__(cls, *args): ++ """Construct an object from a blob or its constituent fields.""" ++ if len(args) == 1: ++ return cls.unpack(args[0]) ++ return cls.__base__.__new__(cls, *args) ++ ++ @staticmethod ++ def unpack(blob: memoryview) -> 'Ident': ++ """Parse raws data into a tuple.""" ++ ei_mag, ei_class, ei_data, ei_version, ei_osabi, ei_abiversion, \ ++ ei_pad = struct.unpack('4s5B7s', blob) ++ return Ident(ei_mag, ElfClass(ei_class), ElfData(ei_data), ++ ei_version, ei_osabi, ei_abiversion, ei_pad) ++ size = 16 ++ ++# Corresponds to Elf32_Ehdr and Elf64_Ehdr. ++Ehdr = collections.namedtuple('Ehdr', ++ 'e_ident e_type e_machine e_version e_entry e_phoff e_shoff e_flags' ++ + ' e_ehsize e_phentsize e_phnum e_shentsize e_shnum e_shstrndx') ++_define_layouts(Ehdr, ++ layout32='16s2H5I6H', ++ layout64='16s2HI3QI6H', ++ types=dict(e_ident=Ident, ++ e_machine=Machine, ++ e_type=Et, ++ e_shstrndx=Shn)) ++ ++# Corresponds to Elf32_Phdr and Elf64_Pdhr. Order follows the latter. ++Phdr = collections.namedtuple('Phdr', ++ 'p_type p_flags p_offset p_vaddr p_paddr p_filesz p_memsz p_align') ++_define_layouts(Phdr, ++ layout32='8I', ++ fields32=('p_type', 'p_offset', 'p_vaddr', 'p_paddr', ++ 'p_filesz', 'p_memsz', 'p_flags', 'p_align'), ++ layout64='2I6Q', ++ types=dict(p_type=Pt, p_flags=Pf)) ++ ++ ++# Corresponds to Elf32_Shdr and Elf64_Shdr. ++class Shdr(collections.namedtuple('Shdr', ++ 'sh_name sh_type sh_flags sh_addr sh_offset sh_size sh_link sh_info' ++ + ' sh_addralign sh_entsize')): ++ def resolve(self, strtab: 'StringTable') -> 'Shdr': ++ """Resolve sh_name using a string table.""" ++ return self.__class__(strtab.get(self[0]), *self[1:]) ++_define_layouts(Shdr, ++ layout32='10I', ++ layout64='2I4Q2I2Q', ++ types=dict(sh_type=Sht, ++ sh_flags=Shf, ++ sh_link=Shn)) ++ ++# Corresponds to Elf32_Dyn and Elf64_Dyn. The nesting through the ++# d_un union is skipped, and d_ptr is missing (its representation in ++# Python would be identical to d_val). ++Dyn = collections.namedtuple('Dyn', 'd_tag d_val') ++_define_layouts(Dyn, ++ layout32='2i', ++ layout64='2q', ++ types=dict(d_tag=Dt)) ++ ++# Corresponds to Elf32_Sym and Elf64_Sym. ++class Sym(collections.namedtuple('Sym', ++ 'st_name st_info st_other st_shndx st_value st_size')): ++ def resolve(self, strtab: 'StringTable') -> 'Sym': ++ """Resolve st_name using a string table.""" ++ return self.__class__(strtab.get(self[0]), *self[1:]) ++_define_layouts(Sym, ++ layout32='3I2BH', ++ layout64='I2BH2Q', ++ fields32=('st_name', 'st_value', 'st_size', 'st_info', ++ 'st_other', 'st_shndx'), ++ types=dict(st_shndx=Shn, ++ st_info=StInfo)) ++ ++# Corresponds to Elf32_Rel and Elf64_Rel. ++Rel = collections.namedtuple('Rel', 'r_offset r_info') ++_define_layouts(Rel, ++ layout32='2I', ++ layout64='2Q') ++ ++# Corresponds to Elf32_Rel and Elf64_Rel. ++Rela = collections.namedtuple('Rela', 'r_offset r_info r_addend') ++_define_layouts(Rela, ++ layout32='3I', ++ layout64='3Q') ++ ++class StringTable: ++ """ELF string table.""" ++ def __init__(self, blob): ++ """Create a new string table backed by the data in the blob. ++ ++ blob: a memoryview-like object ++ ++ """ ++ self.blob = blob ++ ++ def get(self, index) -> bytes: ++ """Returns the null-terminated byte string at the index.""" ++ blob = self.blob ++ endindex = index ++ while True: ++ if blob[endindex] == 0: ++ return bytes(blob[index:endindex]) ++ endindex += 1 ++ ++class Image: ++ """ELF image parser.""" ++ def __init__(self, image): ++ """Create an ELF image from binary image data. ++ ++ image: a memoryview-like object that supports efficient range ++ subscripting. ++ ++ """ ++ self.image = image ++ ident = self.read(Ident, 0) ++ classdata = (ident.ei_class, ident.ei_data) ++ # Set self.Ehdr etc. to the subtypes with the right parsers. ++ for typ in (Ehdr, Phdr, Shdr, Dyn, Sym, Rel, Rela): ++ setattr(self, typ.__name__, typ.layouts.get(classdata, None)) ++ ++ if self.Ehdr is not None: ++ self.ehdr = self.read(self.Ehdr, 0) ++ self._shdr_num = self._compute_shdr_num() ++ else: ++ self.ehdr = None ++ self._shdr_num = 0 ++ ++ self._section = {} ++ self._stringtab = {} ++ ++ if self._shdr_num > 0: ++ self._shdr_strtab = self._find_shdr_strtab() ++ else: ++ self._shdr_strtab = None ++ ++ @staticmethod ++ def readfile(path: str) -> 'Image': ++ """Reads the ELF file at the specified path.""" ++ with open(path, 'rb') as inp: ++ return Image(memoryview(inp.read())) ++ ++ def _compute_shdr_num(self) -> int: ++ """Computes the actual number of section headers.""" ++ shnum = self.ehdr.e_shnum ++ if shnum == 0: ++ if self.ehdr.e_shoff == 0 or self.ehdr.e_shentsize == 0: ++ # No section headers. ++ return 0 ++ # Otherwise the extension mechanism is used (which may be ++ # needed because e_shnum is just 16 bits). ++ return self.read(self.Shdr, self.ehdr.e_shoff).sh_size ++ return shnum ++ ++ def _find_shdr_strtab(self) -> StringTable: ++ """Finds the section header string table (maybe via extensions).""" ++ shstrndx = self.ehdr.e_shstrndx ++ if shstrndx == Shn.SHN_XINDEX: ++ shstrndx = self.read(self.Shdr, self.ehdr.e_shoff).sh_link ++ return self._find_stringtab(shstrndx) ++ ++ def read(self, typ: type, offset:int ): ++ """Reads an object at a specific offset. ++ ++ The type must have been enhanced using _define_variants. ++ ++ """ ++ return typ.unpack(self.image[offset: offset + typ.size]) ++ ++ def phdrs(self) -> Phdr: ++ """Generator iterating over the program headers.""" ++ if self.ehdr is None: ++ return ++ size = self.ehdr.e_phentsize ++ if size != self.Phdr.size: ++ raise ValueError('Unexpected Phdr size in ELF header: {} != {}' ++ .format(size, self.Phdr.size)) ++ ++ offset = self.ehdr.e_phoff ++ for _ in range(self.ehdr.e_phnum): ++ yield self.read(self.Phdr, offset) ++ offset += size ++ ++ def shdrs(self, resolve: bool=True) -> Shdr: ++ """Generator iterating over the section headers. ++ ++ If resolve, section names are automatically translated ++ using the section header string table. ++ ++ """ ++ if self._shdr_num == 0: ++ return ++ ++ size = self.ehdr.e_shentsize ++ if size != self.Shdr.size: ++ raise ValueError('Unexpected Shdr size in ELF header: {} != {}' ++ .format(size, self.Shdr.size)) ++ ++ offset = self.ehdr.e_shoff ++ for _ in range(self._shdr_num): ++ shdr = self.read(self.Shdr, offset) ++ if resolve: ++ shdr = shdr.resolve(self._shdr_strtab) ++ yield shdr ++ offset += size ++ ++ def dynamic(self) -> Dyn: ++ """Generator iterating over the dynamic segment.""" ++ for phdr in self.phdrs(): ++ if phdr.p_type == Pt.PT_DYNAMIC: ++ # Pick the first dynamic segment, like the loader. ++ if phdr.p_filesz == 0: ++ # Probably separated debuginfo. ++ return ++ offset = phdr.p_offset ++ end = offset + phdr.p_memsz ++ size = self.Dyn.size ++ while True: ++ next_offset = offset + size ++ if next_offset > end: ++ raise ValueError( ++ 'Dynamic segment size {} is not a multiple of Dyn size {}'.format( ++ phdr.p_memsz, size)) ++ yield self.read(self.Dyn, offset) ++ if next_offset == end: ++ return ++ offset = next_offset ++ ++ def syms(self, shdr: Shdr, resolve: bool=True) -> Sym: ++ """A generator iterating over a symbol table. ++ ++ If resolve, symbol names are automatically translated using ++ the string table for the symbol table. ++ ++ """ ++ assert shdr.sh_type == Sht.SHT_SYMTAB ++ size = shdr.sh_entsize ++ if size != self.Sym.size: ++ raise ValueError('Invalid symbol table entry size {}'.format(size)) ++ offset = shdr.sh_offset ++ end = shdr.sh_offset + shdr.sh_size ++ if resolve: ++ strtab = self._find_stringtab(shdr.sh_link) ++ while offset < end: ++ sym = self.read(self.Sym, offset) ++ if resolve: ++ sym = sym.resolve(strtab) ++ yield sym ++ offset += size ++ if offset != end: ++ raise ValueError('Symbol table is not a multiple of entry size') ++ ++ def lookup_string(self, strtab_index: int, strtab_offset: int) -> bytes: ++ """Looks up a string in a string table identified by its link index.""" ++ try: ++ strtab = self._stringtab[strtab_index] ++ except KeyError: ++ strtab = self._find_stringtab(strtab_index) ++ return strtab.get(strtab_offset) ++ ++ def find_section(self, shndx: Shn) -> Shdr: ++ """Returns the section header for the indexed section. ++ ++ The section name is not resolved. ++ """ ++ try: ++ return self._section[shndx] ++ except KeyError: ++ pass ++ if shndx in Shn: ++ raise ValueError('Reserved section index {}'.format(shndx)) ++ idx = shndx.value ++ if idx < 0 or idx > self._shdr_num: ++ raise ValueError('Section index {} out of range [0, {})'.format( ++ idx, self._shdr_num)) ++ shdr = self.read( ++ self.Shdr, self.ehdr.e_shoff + idx * self.Shdr.size) ++ self._section[shndx] = shdr ++ return shdr ++ ++ def _find_stringtab(self, sh_link: int) -> StringTable: ++ if sh_link in self._stringtab: ++ return self._stringtab ++ if sh_link < 0 or sh_link >= self._shdr_num: ++ raise ValueError('Section index {} out of range [0, {})'.format( ++ sh_link, self._shdr_num)) ++ shdr = self.read( ++ self.Shdr, self.ehdr.e_shoff + sh_link * self.Shdr.size) ++ if shdr.sh_type != Sht.SHT_STRTAB: ++ raise ValueError( ++ 'Section {} is not a string table: {}'.format( ++ sh_link, shdr.sh_type)) ++ strtab = StringTable( ++ self.image[shdr.sh_offset:shdr.sh_offset + shdr.sh_size]) ++ # This could retrain essentially arbitrary amounts of data, ++ # but caching string tables seems important for performance. ++ self._stringtab[sh_link] = strtab ++ return strtab ++ ++ ++__all__ = [name for name in dir() if name[0].isupper()] diff --git a/glibc-rh2109510-11.patch b/glibc-rh2109510-11.patch new file mode 100644 index 0000000..c7e08fc --- /dev/null +++ b/glibc-rh2109510-11.patch @@ -0,0 +1,409 @@ +commit 198abcbb94618730dae1b3f4393efaa49e0ec8c7 +Author: Florian Weimer +Date: Mon Apr 11 11:30:31 2022 +0200 + + Default to --with-default-link=no (bug 25812) + + This is necessary to place the libio vtables into the RELRO segment. + New tests elf/tst-relro-ldso and elf/tst-relro-libc are added to + verify that this is what actually happens. + + The new tests fail on ia64 due to lack of (default) RELRO support + inbutils, so they are XFAILed there. + +Conflicts: + elf/Makefile + (missing valgrind smoke test) + +diff --git a/INSTALL b/INSTALL +index b3a4370f592c5047..b69672b283c0b774 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -90,6 +90,12 @@ if 'CFLAGS' is specified it must enable optimization. For example: + library will still be usable, but functionality may be lost--for + example, you can't build a shared libc with old binutils. + ++'--with-default-link=FLAG' ++ With '--with-default-link=yes', the build system does not use a ++ custom linker script for linking shared objects. The default for ++ FLAG is the opposite, 'no', because the custom linker script is ++ needed for full RELRO protection. ++ + '--with-nonshared-cflags=CFLAGS' + Use additional compiler flags CFLAGS to build the parts of the + library which are always statically linked into applications and +diff --git a/configure b/configure +index 8b3681d2e28310c8..c794cea4359b3da3 100755 +--- a/configure ++++ b/configure +@@ -3339,7 +3339,7 @@ fi + if test "${with_default_link+set}" = set; then : + withval=$with_default_link; use_default_link=$withval + else +- use_default_link=default ++ use_default_link=no + fi + + +@@ -5965,69 +5965,6 @@ fi + $as_echo "$libc_cv_hashstyle" >&6; } + + +-# The linker's default -shared behavior is good enough if it +-# does these things that our custom linker scripts ensure that +-# all allocated NOTE sections come first. +-if test "$use_default_link" = default; then +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sufficient default -shared layout" >&5 +-$as_echo_n "checking for sufficient default -shared layout... " >&6; } +-if ${libc_cv_use_default_link+:} false; then : +- $as_echo_n "(cached) " >&6 +-else +- libc_cv_use_default_link=no +- cat > conftest.s <<\EOF +- .section .note.a,"a",%note +- .balign 4 +- .long 4,4,9 +- .string "GNU" +- .string "foo" +- .section .note.b,"a",%note +- .balign 4 +- .long 4,4,9 +- .string "GNU" +- .string "bar" +-EOF +- if { ac_try=' ${CC-cc} $ASFLAGS -shared -o conftest.so conftest.s 1>&5' +- { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 +- (eval $ac_try) 2>&5 +- ac_status=$? +- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 +- test $ac_status = 0; }; } && +- ac_try=`$READELF -S conftest.so | sed -n \ +- '${x;p;} +- s/^ *\[ *[1-9][0-9]*\] *\([^ ][^ ]*\) *\([^ ][^ ]*\) .*$/\2 \1/ +- t a +- b +- : a +- H'` +- then +- libc_seen_a=no libc_seen_b=no +- set -- $ac_try +- while test $# -ge 2 -a "$1" = NOTE; do +- case "$2" in +- .note.a) libc_seen_a=yes ;; +- .note.b) libc_seen_b=yes ;; +- esac +- shift 2 +- done +- case "$libc_seen_a$libc_seen_b" in +- yesyes) +- libc_cv_use_default_link=yes +- ;; +- *) +- echo >&5 "\ +-$libc_seen_a$libc_seen_b from: +-$ac_try" +- ;; +- esac +- fi +- rm -f conftest* +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_use_default_link" >&5 +-$as_echo "$libc_cv_use_default_link" >&6; } +- use_default_link=$libc_cv_use_default_link +-fi +- + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLOB_DAT reloc" >&5 + $as_echo_n "checking for GLOB_DAT reloc... " >&6; } + if ${libc_cv_has_glob_dat+:} false; then : +diff --git a/configure.ac b/configure.ac +index 82d9ab2fb67145bb..52429d82344954b3 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -152,7 +152,7 @@ AC_ARG_WITH([default-link], + AC_HELP_STRING([--with-default-link], + [do not use explicit linker scripts]), + [use_default_link=$withval], +- [use_default_link=default]) ++ [use_default_link=no]) + + dnl Additional build flags injection. + AC_ARG_WITH([nonshared-cflags], +@@ -1352,59 +1352,6 @@ fi + rm -f conftest*]) + AC_SUBST(libc_cv_hashstyle) + +-# The linker's default -shared behavior is good enough if it +-# does these things that our custom linker scripts ensure that +-# all allocated NOTE sections come first. +-if test "$use_default_link" = default; then +- AC_CACHE_CHECK([for sufficient default -shared layout], +- libc_cv_use_default_link, [dnl +- libc_cv_use_default_link=no +- cat > conftest.s <<\EOF +- .section .note.a,"a",%note +- .balign 4 +- .long 4,4,9 +- .string "GNU" +- .string "foo" +- .section .note.b,"a",%note +- .balign 4 +- .long 4,4,9 +- .string "GNU" +- .string "bar" +-EOF +- if AC_TRY_COMMAND([dnl +- ${CC-cc} $ASFLAGS -shared -o conftest.so conftest.s 1>&AS_MESSAGE_LOG_FD]) && +- ac_try=`$READELF -S conftest.so | sed -n \ +- ['${x;p;} +- s/^ *\[ *[1-9][0-9]*\] *\([^ ][^ ]*\) *\([^ ][^ ]*\) .*$/\2 \1/ +- t a +- b +- : a +- H']` +- then +- libc_seen_a=no libc_seen_b=no +- set -- $ac_try +- while test $# -ge 2 -a "$1" = NOTE; do +- case "$2" in +- .note.a) libc_seen_a=yes ;; +- .note.b) libc_seen_b=yes ;; +- esac +- shift 2 +- done +- case "$libc_seen_a$libc_seen_b" in +- yesyes) +- libc_cv_use_default_link=yes +- ;; +- *) +- echo >&AS_MESSAGE_LOG_FD "\ +-$libc_seen_a$libc_seen_b from: +-$ac_try" +- ;; +- esac +- fi +- rm -f conftest*]) +- use_default_link=$libc_cv_use_default_link +-fi +- + AC_CACHE_CHECK(for GLOB_DAT reloc, + libc_cv_has_glob_dat, [dnl + cat > conftest.c < $@ 2>&1; $(evaluate-test) ++# The optional symbols are present in libc only if the architecture has ++# the GLIBC_2.0 symbol set in libc. ++$(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \ ++ $(common-objpfx)libc.so ++ $(PYTHON) tst-relro-symbols.py $(common-objpfx)libc.so \ ++ --required=_IO_cookie_jumps \ ++ --required=_IO_file_jumps \ ++ --required=_IO_file_jumps_maybe_mmap \ ++ --required=_IO_file_jumps_mmap \ ++ --required=_IO_helper_jumps \ ++ --required=_IO_mem_jumps \ ++ --required=_IO_obstack_jumps \ ++ --required=_IO_proc_jumps \ ++ --required=_IO_str_chk_jumps \ ++ --required=_IO_str_jumps \ ++ --required=_IO_strn_jumps \ ++ --required=_IO_wfile_jumps \ ++ --required=_IO_wfile_jumps_maybe_mmap \ ++ --required=_IO_wfile_jumps_mmap \ ++ --required=_IO_wmem_jumps \ ++ --required=_IO_wstr_jumps \ ++ --required=_IO_wstrn_jumps \ ++ --optional=_IO_old_cookie_jumps \ ++ --optional=_IO_old_file_jumps \ ++ --optional=_IO_old_proc_jumps \ ++ > $@ 2>&1; $(evaluate-test) ++ + tests += $(tests-execstack-$(have-z-execstack)) + ifeq ($(run-built-tests),yes) + tests-special += \ +diff --git a/elf/tst-relro-symbols.py b/elf/tst-relro-symbols.py +new file mode 100644 +index 0000000000000000..368ea3349f86bd81 +--- /dev/null ++++ b/elf/tst-relro-symbols.py +@@ -0,0 +1,137 @@ ++#!/usr/bin/python3 ++# Verify that certain symbols are covered by RELRO. ++# 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 ++# . ++ ++"""Analyze a (shared) object to verify that certain symbols are ++present and covered by the PT_GNU_RELRO segment. ++ ++""" ++ ++import argparse ++import os.path ++import sys ++ ++# Make available glibc Python modules. ++sys.path.append(os.path.join( ++ os.path.dirname(os.path.realpath(__file__)), os.path.pardir, 'scripts')) ++ ++import glibcelf ++ ++def find_relro(path: str, img: glibcelf.Image) -> (int, int): ++ """Discover the address range of the PT_GNU_RELRO segment.""" ++ for phdr in img.phdrs(): ++ if phdr.p_type == glibcelf.Pt.PT_GNU_RELRO: ++ # The computation is not entirely accurate because ++ # _dl_protect_relro in elf/dl-reloc.c rounds both the ++ # start end and downwards using the run-time page size. ++ return phdr.p_vaddr, phdr.p_vaddr + phdr.p_memsz ++ sys.stdout.write('{}: error: no PT_GNU_RELRO segment\n'.format(path)) ++ sys.exit(1) ++ ++def check_in_relro(kind, relro_begin, relro_end, name, start, size, error): ++ """Check if a section or symbol falls within in the RELRO segment.""" ++ end = start + size - 1 ++ if not (relro_begin <= start < end < relro_end): ++ error( ++ '{} {!r} of size {} at 0x{:x} is not in RELRO range [0x{:x}, 0x{:x})'.format( ++ kind, name.decode('UTF-8'), start, size, ++ relro_begin, relro_end)) ++ ++def get_parser(): ++ """Return an argument parser for this script.""" ++ parser = argparse.ArgumentParser(description=__doc__) ++ parser.add_argument('object', help='path to object file to check') ++ parser.add_argument('--required', metavar='NAME', default=(), ++ help='required symbol names', nargs='*') ++ parser.add_argument('--optional', metavar='NAME', default=(), ++ help='required symbol names', nargs='*') ++ return parser ++ ++def main(argv): ++ """The main entry point.""" ++ parser = get_parser() ++ opts = parser.parse_args(argv) ++ img = glibcelf.Image.readfile(opts.object) ++ ++ required_symbols = frozenset([sym.encode('UTF-8') ++ for sym in opts.required]) ++ optional_symbols = frozenset([sym.encode('UTF-8') ++ for sym in opts.optional]) ++ check_symbols = required_symbols | optional_symbols ++ ++ # Tracks the symbols in check_symbols that have been found. ++ symbols_found = set() ++ ++ # Discover the extent of the RELRO segment. ++ relro_begin, relro_end = find_relro(opts.object, img) ++ symbol_table_found = False ++ ++ errors = False ++ def error(msg: str) -> None: ++ """Record an error condition and write a message to standard output.""" ++ nonlocal errors ++ errors = True ++ sys.stdout.write('{}: error: {}\n'.format(opts.object, msg)) ++ ++ # Iterate over section headers to find the symbol table. ++ for shdr in img.shdrs(): ++ if shdr.sh_type == glibcelf.Sht.SHT_SYMTAB: ++ symbol_table_found = True ++ for sym in img.syms(shdr): ++ if sym.st_name in check_symbols: ++ symbols_found.add(sym.st_name) ++ ++ # Validate symbol type, section, and size. ++ if sym.st_info.type != glibcelf.Stt.STT_OBJECT: ++ error('symbol {!r} has wrong type {}'.format( ++ sym.st_name.decode('UTF-8'), sym.st_info.type)) ++ if sym.st_shndx in glibcelf.Shn: ++ error('symbol {!r} has reserved section {}'.format( ++ sym.st_name.decode('UTF-8'), sym.st_shndx)) ++ continue ++ if sym.st_size == 0: ++ error('symbol {!r} has size zero'.format( ++ sym.st_name.decode('UTF-8'))) ++ continue ++ ++ check_in_relro('symbol', relro_begin, relro_end, ++ sym.st_name, sym.st_value, sym.st_size, ++ error) ++ continue # SHT_SYMTAB ++ if shdr.sh_name == b'.data.rel.ro' \ ++ or shdr.sh_name.startswith(b'.data.rel.ro.'): ++ check_in_relro('section', relro_begin, relro_end, ++ shdr.sh_name, shdr.sh_addr, shdr.sh_size, ++ error) ++ continue ++ ++ if required_symbols - symbols_found: ++ for sym in sorted(required_symbols - symbols_found): ++ error('symbol {!r} not found'.format(sym.decode('UTF-8'))) ++ ++ if errors: ++ sys.exit(1) ++ ++ if not symbol_table_found: ++ sys.stdout.write( ++ '{}: warning: no symbol table found (stripped object)\n'.format( ++ opts.object)) ++ sys.exit(77) ++ ++if __name__ == '__main__': ++ main(sys.argv[1:]) +diff --git a/manual/install.texi b/manual/install.texi +index c262fd56d0cef67b..a2c43bd692de7825 100644 +--- a/manual/install.texi ++++ b/manual/install.texi +@@ -117,6 +117,12 @@ problem and suppress these constructs, so that the library will still be + usable, but functionality may be lost---for example, you can't build a + shared libc with old binutils. + ++@item --with-default-link=@var{FLAG} ++With @code{--with-default-link=yes}, the build system does not use a ++custom linker script for linking shared objects. The default for ++@var{FLAG} is the opposite, @samp{no}, because the custom linker script ++is needed for full RELRO protection. ++ + @item --with-nonshared-cflags=@var{cflags} + Use additional compiler flags @var{cflags} to build the parts of the + library which are always statically linked into applications and +diff --git a/sysdeps/unix/sysv/linux/ia64/Makefile b/sysdeps/unix/sysv/linux/ia64/Makefile +index 97fc7df0b122d6a0..b1ad1ab7b1efa34c 100644 +--- a/sysdeps/unix/sysv/linux/ia64/Makefile ++++ b/sysdeps/unix/sysv/linux/ia64/Makefile +@@ -1,3 +1,9 @@ ++ifeq ($(subdir),elf) ++# ia64 does not support PT_GNU_RELRO. ++test-xfail-tst-relro-ldso = yes ++test-xfail-tst-relro-libc = yes ++endif ++ + ifeq ($(subdir),misc) + sysdep_headers += sys/rse.h + endif diff --git a/glibc-rh2109510-12.patch b/glibc-rh2109510-12.patch new file mode 100644 index 0000000..a580b1b --- /dev/null +++ b/glibc-rh2109510-12.patch @@ -0,0 +1,26 @@ +commit b571f3adffdcbed23f35ea39b0ca43809dbb4f5b +Author: Florian Weimer +Date: Fri Apr 22 19:34:52 2022 +0200 + + scripts/glibcelf.py: Mark as UNSUPPORTED on Python 3.5 and earlier + + enum.IntFlag and enum.EnumMeta._missing_ support are not part of + earlier Python versions. + +diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py +index 8f7d0ca184845714..da0d5380f33a195e 100644 +--- a/scripts/glibcelf.py ++++ b/scripts/glibcelf.py +@@ -28,6 +28,12 @@ import collections + import enum + import struct + ++if not hasattr(enum, 'IntFlag'): ++ import sys ++ sys.stdout.write( ++ 'warning: glibcelf.py needs Python 3.6 for enum support\n') ++ sys.exit(77) ++ + class _OpenIntEnum(enum.IntEnum): + """Integer enumeration that supports arbitrary int values.""" + @classmethod diff --git a/glibc-rh2109510-13.patch b/glibc-rh2109510-13.patch new file mode 100644 index 0000000..8589a81 --- /dev/null +++ b/glibc-rh2109510-13.patch @@ -0,0 +1,30 @@ +Partial backport of the scripts/glibcelf.py part of: + +commit 4610b24f5e4e6d2c4b769594efa6d460943163bb +Author: H.J. Lu +Date: Tue Mar 29 14:08:54 2022 -0700 + + elf: Define DT_RELR related macros and types + +diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py +index da0d5380f33a195e..f847b36c55c15b8a 100644 +--- a/scripts/glibcelf.py ++++ b/scripts/glibcelf.py +@@ -304,6 +304,7 @@ class Sht(_OpenIntEnum): + SHT_PREINIT_ARRAY = 16 + SHT_GROUP = 17 + SHT_SYMTAB_SHNDX = 18 ++ SHT_RELR = 19 + SHT_GNU_ATTRIBUTES = 0x6ffffff5 + SHT_GNU_HASH = 0x6ffffff6 + SHT_GNU_LIBLIST = 0x6ffffff7 +@@ -593,6 +594,9 @@ class Dt(_OpenIntEnum): + DT_PREINIT_ARRAY = 32 + DT_PREINIT_ARRAYSZ = 33 + DT_SYMTAB_SHNDX = 34 ++ DT_RELRSZ = 35 ++ DT_RELR = 36 ++ DT_RELRENT = 37 + DT_GNU_PRELINKED = 0x6ffffdf5 + DT_GNU_CONFLICTSZ = 0x6ffffdf6 + DT_GNU_LIBLISTSZ = 0x6ffffdf7 diff --git a/glibc-rh2109510-14.patch b/glibc-rh2109510-14.patch new file mode 100644 index 0000000..9448450 --- /dev/null +++ b/glibc-rh2109510-14.patch @@ -0,0 +1,50 @@ +commit d055481ce39d03652ac60de5078889e15b6917ff +Author: Florian Weimer +Date: Mon May 16 21:59:24 2022 +0200 + + scripts/glibcelf.py: Add *T_RISCV_* constants + + SHT_RISCV_ATTRIBUTES, PT_RISCV_ATTRIBUTES, DT_RISCV_VARIANT_CC were + added in commit 0b6c6750732483b4d59c2fcb45484079cd84157d + ("Update RISC-V specific ELF definitions"). This caused the + elf/tst-glibcelf consistency check to fail. + + Reviewed-by: Adhemerval Zanella + +diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py +index f847b36c55c15b8a..07bef940433b4c99 100644 +--- a/scripts/glibcelf.py ++++ b/scripts/glibcelf.py +@@ -385,6 +385,10 @@ class ShtPARISC(enum.Enum): + SHT_PARISC_UNWIND = 0x70000001 + SHT_PARISC_DOC = 0x70000002 + ++class ShtRISCV(enum.Enum): ++ """Supplemental SHT_* constants for EM_RISCV.""" ++ SHT_RISCV_ATTRIBUTES = 0x70000003 ++ + class Pf(enum.IntFlag): + """Program header flags. Type of Phdr.p_flags values.""" + PF_X = 1 +@@ -558,6 +562,10 @@ class PtPARISC(enum.Enum): + PT_PARISC_ARCHEXT = 0x70000000 + PT_PARISC_UNWIND = 0x70000001 + ++class PtRISCV(enum.Enum): ++ """Supplemental PT_* constants for EM_RISCV.""" ++ PT_RISCV_ATTRIBUTES = 0x70000003 ++ + class Dt(_OpenIntEnum): + """ELF dynamic segment tags. Type of Dyn.d_val.""" + DT_NULL = 0 +@@ -710,6 +718,10 @@ class DtPPC64(enum.Enum): + DT_PPC64_OPDSZ = 0x70000002 + DT_PPC64_OPT = 0x70000003 + ++class DtRISCV(enum.Enum): ++ """Supplemental DT_* constants for EM_RISCV.""" ++ DT_RISCV_VARIANT_CC = 0x70000001 ++ + class DtSPARC(enum.Enum): + """Supplemental DT_* constants for EM_SPARC.""" + DT_SPARC_REGISTER = 0x70000001 diff --git a/glibc-rh2109510-15.patch b/glibc-rh2109510-15.patch new file mode 100644 index 0000000..7979be8 --- /dev/null +++ b/glibc-rh2109510-15.patch @@ -0,0 +1,26 @@ +commit 8521001731d6539382fa875f1cac9864c466ef27 +Author: Adhemerval Zanella +Date: Mon Jun 6 14:41:24 2022 -0300 + + scripts/glibcelf.py: Add PT_AARCH64_MEMTAG_MTE constant + + It was added in commit 603e5c8ba7257483c162cabb06eb6f79096429b6. + This caused the elf/tst-glibcelf consistency check to fail. + + Reviewed-by: Florian Weimer + +diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py +index 07bef940433b4c99..47f95d07baefb4ae 100644 +--- a/scripts/glibcelf.py ++++ b/scripts/glibcelf.py +@@ -523,6 +523,10 @@ class Pt(_OpenIntEnum): + PT_SUNWBSS = 0x6ffffffa + PT_SUNWSTACK = 0x6ffffffb + ++class PtAARCH64(enum.Enum): ++ """Supplemental PT_* constants for EM_AARCH64.""" ++ PT_AARCH64_MEMTAG_MTE = 0x70000002 ++ + class PtARM(enum.Enum): + """Supplemental PT_* constants for EM_ARM.""" + PT_ARM_EXIDX = 0x70000001 diff --git a/glibc-rh2109510-16.patch b/glibc-rh2109510-16.patch new file mode 100644 index 0000000..38416a0 --- /dev/null +++ b/glibc-rh2109510-16.patch @@ -0,0 +1,22 @@ +Partial backport of the scripts/glibcelf.py part of: + +commit 2d83247d90c9f0bfee7f3f2505bc1b13b6f36c04 +Author: caiyinyu +Date: Tue Jul 19 09:20:45 2022 +0800 + + LoongArch: Add relocations and ELF flags to elf.h and scripts/glibcelf.py + +diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py +index 47f95d07baefb4ae..de0509130ed9ad47 100644 +--- a/scripts/glibcelf.py ++++ b/scripts/glibcelf.py +@@ -252,7 +252,8 @@ class Machine(_OpenIntEnum): + EM_RISCV = 243 + EM_BPF = 247 + EM_CSKY = 252 +- EM_NUM = 253 ++ EM_LOONGARCH = 258 ++ EM_NUM = 259 + EM_ALPHA = 0x9026 + + class Et(_OpenIntEnum): diff --git a/glibc-rh2109510-17.patch b/glibc-rh2109510-17.patch new file mode 100644 index 0000000..a7e5a3a --- /dev/null +++ b/glibc-rh2109510-17.patch @@ -0,0 +1,78 @@ +commit bd13cb19f5e15e9e9a92a536e755fd93a97a67f6 +Author: Florian Weimer +Date: Fri Aug 19 11:16:32 2022 +0200 + + scripts/glibcelf.py: Add hashing support + + ELF and GNU hashes can now be computed using the elf_hash and + gnu_hash functions. + + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + +diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py +index bf15a3bad4479e08..e5026e2289df206b 100644 +--- a/elf/tst-glibcelf.py ++++ b/elf/tst-glibcelf.py +@@ -240,6 +240,24 @@ def check_constant_values(cc): + error('{}: glibcelf has {!r}, has {!r}'.format( + name, glibcelf_value, elf_h_value)) + ++def check_hashes(): ++ for name, expected_elf, expected_gnu in ( ++ ('', 0, 0x1505), ++ ('PPPPPPPPPPPP', 0, 0x9f105c45), ++ ('GLIBC_2.0', 0xd696910, 0xf66c3dd5), ++ ('GLIBC_2.34', 0x69691b4, 0xc3f3f90c), ++ ('GLIBC_PRIVATE', 0x963cf85, 0x692a260)): ++ for convert in (lambda x: x, lambda x: x.encode('UTF-8')): ++ name = convert(name) ++ actual_elf = glibcelf.elf_hash(name) ++ if actual_elf != expected_elf: ++ error('elf_hash({!r}): {:x} != 0x{:x}'.format( ++ name, actual_elf, expected_elf)) ++ actual_gnu = glibcelf.gnu_hash(name) ++ if actual_gnu != expected_gnu: ++ error('gnu_hash({!r}): {:x} != 0x{:x}'.format( ++ name, actual_gnu, expected_gnu)) ++ + def main(): + """The main entry point.""" + parser = argparse.ArgumentParser( +@@ -251,6 +269,7 @@ def main(): + check_duplicates() + check_constant_prefixes() + check_constant_values(cc=args.cc) ++ check_hashes() + + if errors_encountered > 0: + print("note: errors encountered:", errors_encountered) +diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py +index de0509130ed9ad47..5c8f46f590722384 100644 +--- a/scripts/glibcelf.py ++++ b/scripts/glibcelf.py +@@ -1158,5 +1158,24 @@ class Image: + self._stringtab[sh_link] = strtab + return strtab + ++def elf_hash(s): ++ """Computes the ELF hash of the string.""" ++ acc = 0 ++ for ch in s: ++ if type(ch) is not int: ++ ch = ord(ch) ++ acc = ((acc << 4) + ch) & 0xffffffff ++ top = acc & 0xf0000000 ++ acc = (acc ^ (top >> 24)) & ~top ++ return acc ++ ++def gnu_hash(s): ++ """Computes the GNU hash of the string.""" ++ h = 5381 ++ for ch in s: ++ if type(ch) is not int: ++ ch = ord(ch) ++ h = (h * 33 + ch) & 0xffffffff ++ return h + + __all__ = [name for name in dir() if name[0].isupper()] diff --git a/glibc-rh2109510-18.patch b/glibc-rh2109510-18.patch new file mode 100644 index 0000000..83172fa --- /dev/null +++ b/glibc-rh2109510-18.patch @@ -0,0 +1,439 @@ +commit f40c7887d3cc9bb0b56576ed9edbe505ff8058c0 +Author: Florian Weimer +Date: Thu Sep 22 12:10:41 2022 +0200 + + scripts: Extract glibcpp.py from check-obsolete-constructs.py + + The C tokenizer is useful separately. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py +index 89d21dea6e788783..7c7a092e440a3258 100755 +--- a/scripts/check-obsolete-constructs.py ++++ b/scripts/check-obsolete-constructs.py +@@ -24,193 +24,14 @@ + """ + + import argparse +-import collections ++import os + import re + import sys + +-# Simplified lexical analyzer for C preprocessing tokens. +-# Does not implement trigraphs. +-# Does not implement backslash-newline in the middle of any lexical +-# item other than a string literal. +-# Does not implement universal-character-names in identifiers. +-# Treats prefixed strings (e.g. L"...") as two tokens (L and "...") +-# Accepts non-ASCII characters only within comments and strings. +- +-# Caution: The order of the outermost alternation matters. +-# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST, +-# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must +-# be last. +-# Caution: There should be no capturing groups other than the named +-# captures in the outermost alternation. +- +-# For reference, these are all of the C punctuators as of C11: +-# [ ] ( ) { } , ; ? ~ +-# ! != * *= / /= ^ ^= = == +-# # ## +-# % %= %> %: %:%: +-# & &= && +-# | |= || +-# + += ++ +-# - -= -- -> +-# . ... +-# : :> +-# < <% <: << <<= <= +-# > >= >> >>= +- +-# The BAD_* tokens are not part of the official definition of pp-tokens; +-# they match unclosed strings, character constants, and block comments, +-# so that the regex engine doesn't have to backtrack all the way to the +-# beginning of a broken construct and then emit dozens of junk tokens. +- +-PP_TOKEN_RE_ = re.compile(r""" +- (?P \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\") +- |(?P \"(?:[^\"\\\r\n]|\\[ -~])*) +- |(?P \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\') +- |(?P \'(?:[^\'\\\r\n]|\\[ -~])*) +- |(?P /\*(?:\*(?!/)|[^*])*\*/) +- |(?P /\*(?:\*(?!/)|[^*])*\*?) +- |(?P //[^\r\n]*) +- |(?P [_a-zA-Z][_a-zA-Z0-9]*) +- |(?P \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*) +- |(?P +- [,;?~(){}\[\]] +- | [!*/^=]=? +- | \#\#? +- | %(?:[=>]|:(?:%:)?)? +- | &[=&]? +- |\|[=|]? +- |\+[=+]? +- | -[=->]? +- |\.(?:\.\.)? +- | :>? +- | <(?:[%:]|<(?:=|<=?)?)? +- | >(?:=|>=?)?) +- |(?P \\(?:\r|\n|\r\n)) +- |(?P [ \t\n\r\v\f]+) +- |(?P .) +-""", re.DOTALL | re.VERBOSE) +- +-HEADER_NAME_RE_ = re.compile(r""" +- < [^>\r\n]+ > +- | " [^"\r\n]+ " +-""", re.DOTALL | re.VERBOSE) +- +-ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""") +- +-# based on the sample code in the Python re documentation +-Token_ = collections.namedtuple("Token", ( +- "kind", "text", "line", "column", "context")) +-Token_.__doc__ = """ +- One C preprocessing token, comment, or chunk of whitespace. +- 'kind' identifies the token type, which will be one of: +- STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT, +- PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME, +- or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are +- handled within tokenize_c, below. +- +- 'text' is the sequence of source characters making up the token; +- no decoding whatsoever is performed. +- +- 'line' and 'column' give the position of the first character of the +- token within the source file. They are both 1-based. +- +- 'context' indicates whether or not this token occurred within a +- preprocessing directive; it will be None for running text, +- '' for the leading '#' of a directive line (because '#' +- all by itself on a line is a "null directive"), or the name of +- the directive for tokens within a directive line, starting with +- the IDENT for the name itself. +-""" +- +-def tokenize_c(file_contents, reporter): +- """Yield a series of Token objects, one for each preprocessing +- token, comment, or chunk of whitespace within FILE_CONTENTS. +- The REPORTER object is expected to have one method, +- reporter.error(token, message), which will be called to +- indicate a lexical error at the position of TOKEN. +- If MESSAGE contains the four-character sequence '{!r}', that +- is expected to be replaced by repr(token.text). +- """ ++# Make available glibc Python modules. ++sys.path.append(os.path.dirname(os.path.realpath(__file__))) + +- Token = Token_ +- PP_TOKEN_RE = PP_TOKEN_RE_ +- ENDLINE_RE = ENDLINE_RE_ +- HEADER_NAME_RE = HEADER_NAME_RE_ +- +- line_num = 1 +- line_start = 0 +- pos = 0 +- limit = len(file_contents) +- directive = None +- at_bol = True +- while pos < limit: +- if directive == "include": +- mo = HEADER_NAME_RE.match(file_contents, pos) +- if mo: +- kind = "HEADER_NAME" +- directive = "after_include" +- else: +- mo = PP_TOKEN_RE.match(file_contents, pos) +- kind = mo.lastgroup +- if kind != "WHITESPACE": +- directive = "after_include" +- else: +- mo = PP_TOKEN_RE.match(file_contents, pos) +- kind = mo.lastgroup +- +- text = mo.group() +- line = line_num +- column = mo.start() - line_start +- adj_line_start = 0 +- # only these kinds can contain a newline +- if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT", +- "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"): +- for tmo in ENDLINE_RE.finditer(text): +- line_num += 1 +- adj_line_start = tmo.end() +- if adj_line_start: +- line_start = mo.start() + adj_line_start +- +- # Track whether or not we are scanning a preprocessing directive. +- if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start): +- at_bol = True +- directive = None +- else: +- if kind == "PUNCTUATOR" and text == "#" and at_bol: +- directive = "" +- elif kind == "IDENT" and directive == "": +- directive = text +- at_bol = False +- +- # Report ill-formed tokens and rewrite them as their well-formed +- # equivalents, so downstream processing doesn't have to know about them. +- # (Rewriting instead of discarding provides better error recovery.) +- if kind == "BAD_BLOCK_COM": +- reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""), +- "unclosed block comment") +- text += "*/" +- kind = "BLOCK_COMMENT" +- elif kind == "BAD_STRING": +- reporter.error(Token("BAD_STRING", "", line, column+1, ""), +- "unclosed string") +- text += "\"" +- kind = "STRING" +- elif kind == "BAD_CHARCONST": +- reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""), +- "unclosed char constant") +- text += "'" +- kind = "CHARCONST" +- +- tok = Token(kind, text, line, column+1, +- "include" if directive == "after_include" else directive) +- # Do not complain about OTHER tokens inside macro definitions. +- # $ and @ appear in macros defined by headers intended to be +- # included from assembly language, e.g. sysdeps/mips/sys/asm.h. +- if kind == "OTHER" and directive != "define": +- self.error(tok, "stray {!r} in program") +- +- yield tok +- pos = mo.end() ++import glibcpp + + # + # Base and generic classes for individual checks. +@@ -446,7 +267,7 @@ class HeaderChecker: + + typedef_checker = ObsoleteTypedefChecker(self, self.fname) + +- for tok in tokenize_c(contents, self): ++ for tok in glibcpp.tokenize_c(contents, self): + typedef_checker.examine(tok) + + def main(): +diff --git a/scripts/glibcpp.py b/scripts/glibcpp.py +new file mode 100644 +index 0000000000000000..b44c6a4392dde8ce +--- /dev/null ++++ b/scripts/glibcpp.py +@@ -0,0 +1,212 @@ ++#! /usr/bin/python3 ++# Approximation to C preprocessing. ++# Copyright (C) 2019-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 ++# . ++ ++""" ++Simplified lexical analyzer for C preprocessing tokens. ++ ++Does not implement trigraphs. ++ ++Does not implement backslash-newline in the middle of any lexical ++item other than a string literal. ++ ++Does not implement universal-character-names in identifiers. ++ ++Treats prefixed strings (e.g. L"...") as two tokens (L and "..."). ++ ++Accepts non-ASCII characters only within comments and strings. ++""" ++ ++import collections ++import re ++ ++# Caution: The order of the outermost alternation matters. ++# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST, ++# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must ++# be last. ++# Caution: There should be no capturing groups other than the named ++# captures in the outermost alternation. ++ ++# For reference, these are all of the C punctuators as of C11: ++# [ ] ( ) { } , ; ? ~ ++# ! != * *= / /= ^ ^= = == ++# # ## ++# % %= %> %: %:%: ++# & &= && ++# | |= || ++# + += ++ ++# - -= -- -> ++# . ... ++# : :> ++# < <% <: << <<= <= ++# > >= >> >>= ++ ++# The BAD_* tokens are not part of the official definition of pp-tokens; ++# they match unclosed strings, character constants, and block comments, ++# so that the regex engine doesn't have to backtrack all the way to the ++# beginning of a broken construct and then emit dozens of junk tokens. ++ ++PP_TOKEN_RE_ = re.compile(r""" ++ (?P \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\") ++ |(?P \"(?:[^\"\\\r\n]|\\[ -~])*) ++ |(?P \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\') ++ |(?P \'(?:[^\'\\\r\n]|\\[ -~])*) ++ |(?P /\*(?:\*(?!/)|[^*])*\*/) ++ |(?P /\*(?:\*(?!/)|[^*])*\*?) ++ |(?P //[^\r\n]*) ++ |(?P [_a-zA-Z][_a-zA-Z0-9]*) ++ |(?P \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*) ++ |(?P ++ [,;?~(){}\[\]] ++ | [!*/^=]=? ++ | \#\#? ++ | %(?:[=>]|:(?:%:)?)? ++ | &[=&]? ++ |\|[=|]? ++ |\+[=+]? ++ | -[=->]? ++ |\.(?:\.\.)? ++ | :>? ++ | <(?:[%:]|<(?:=|<=?)?)? ++ | >(?:=|>=?)?) ++ |(?P \\(?:\r|\n|\r\n)) ++ |(?P [ \t\n\r\v\f]+) ++ |(?P .) ++""", re.DOTALL | re.VERBOSE) ++ ++HEADER_NAME_RE_ = re.compile(r""" ++ < [^>\r\n]+ > ++ | " [^"\r\n]+ " ++""", re.DOTALL | re.VERBOSE) ++ ++ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""") ++ ++# based on the sample code in the Python re documentation ++Token_ = collections.namedtuple("Token", ( ++ "kind", "text", "line", "column", "context")) ++Token_.__doc__ = """ ++ One C preprocessing token, comment, or chunk of whitespace. ++ 'kind' identifies the token type, which will be one of: ++ STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT, ++ PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME, ++ or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are ++ handled within tokenize_c, below. ++ ++ 'text' is the sequence of source characters making up the token; ++ no decoding whatsoever is performed. ++ ++ 'line' and 'column' give the position of the first character of the ++ token within the source file. They are both 1-based. ++ ++ 'context' indicates whether or not this token occurred within a ++ preprocessing directive; it will be None for running text, ++ '' for the leading '#' of a directive line (because '#' ++ all by itself on a line is a "null directive"), or the name of ++ the directive for tokens within a directive line, starting with ++ the IDENT for the name itself. ++""" ++ ++def tokenize_c(file_contents, reporter): ++ """Yield a series of Token objects, one for each preprocessing ++ token, comment, or chunk of whitespace within FILE_CONTENTS. ++ The REPORTER object is expected to have one method, ++ reporter.error(token, message), which will be called to ++ indicate a lexical error at the position of TOKEN. ++ If MESSAGE contains the four-character sequence '{!r}', that ++ is expected to be replaced by repr(token.text). ++ """ ++ ++ Token = Token_ ++ PP_TOKEN_RE = PP_TOKEN_RE_ ++ ENDLINE_RE = ENDLINE_RE_ ++ HEADER_NAME_RE = HEADER_NAME_RE_ ++ ++ line_num = 1 ++ line_start = 0 ++ pos = 0 ++ limit = len(file_contents) ++ directive = None ++ at_bol = True ++ while pos < limit: ++ if directive == "include": ++ mo = HEADER_NAME_RE.match(file_contents, pos) ++ if mo: ++ kind = "HEADER_NAME" ++ directive = "after_include" ++ else: ++ mo = PP_TOKEN_RE.match(file_contents, pos) ++ kind = mo.lastgroup ++ if kind != "WHITESPACE": ++ directive = "after_include" ++ else: ++ mo = PP_TOKEN_RE.match(file_contents, pos) ++ kind = mo.lastgroup ++ ++ text = mo.group() ++ line = line_num ++ column = mo.start() - line_start ++ adj_line_start = 0 ++ # only these kinds can contain a newline ++ if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT", ++ "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"): ++ for tmo in ENDLINE_RE.finditer(text): ++ line_num += 1 ++ adj_line_start = tmo.end() ++ if adj_line_start: ++ line_start = mo.start() + adj_line_start ++ ++ # Track whether or not we are scanning a preprocessing directive. ++ if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start): ++ at_bol = True ++ directive = None ++ else: ++ if kind == "PUNCTUATOR" and text == "#" and at_bol: ++ directive = "" ++ elif kind == "IDENT" and directive == "": ++ directive = text ++ at_bol = False ++ ++ # Report ill-formed tokens and rewrite them as their well-formed ++ # equivalents, so downstream processing doesn't have to know about them. ++ # (Rewriting instead of discarding provides better error recovery.) ++ if kind == "BAD_BLOCK_COM": ++ reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""), ++ "unclosed block comment") ++ text += "*/" ++ kind = "BLOCK_COMMENT" ++ elif kind == "BAD_STRING": ++ reporter.error(Token("BAD_STRING", "", line, column+1, ""), ++ "unclosed string") ++ text += "\"" ++ kind = "STRING" ++ elif kind == "BAD_CHARCONST": ++ reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""), ++ "unclosed char constant") ++ text += "'" ++ kind = "CHARCONST" ++ ++ tok = Token(kind, text, line, column+1, ++ "include" if directive == "after_include" else directive) ++ # Do not complain about OTHER tokens inside macro definitions. ++ # $ and @ appear in macros defined by headers intended to be ++ # included from assembly language, e.g. sysdeps/mips/sys/asm.h. ++ if kind == "OTHER" and directive != "define": ++ self.error(tok, "stray {!r} in program") ++ ++ yield tok ++ pos = mo.end() diff --git a/glibc-rh2109510-19.patch b/glibc-rh2109510-19.patch new file mode 100644 index 0000000..f77b415 --- /dev/null +++ b/glibc-rh2109510-19.patch @@ -0,0 +1,598 @@ +commit e6e6184bed490403811771fa527eb95b4ae53c7c +Author: Florian Weimer +Date: Thu Sep 22 12:10:41 2022 +0200 + + scripts: Enhance glibcpp to do basic macro processing + + Reviewed-by: Siddhesh Poyarekar + +Conflicts: + support/Makefile + (spurious tests sorting change upstream) + +diff --git a/scripts/glibcpp.py b/scripts/glibcpp.py +index b44c6a4392dde8ce..455459a609eab120 100644 +--- a/scripts/glibcpp.py ++++ b/scripts/glibcpp.py +@@ -33,7 +33,9 @@ Accepts non-ASCII characters only within comments and strings. + """ + + import collections ++import operator + import re ++import sys + + # Caution: The order of the outermost alternation matters. + # STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST, +@@ -210,3 +212,318 @@ def tokenize_c(file_contents, reporter): + + yield tok + pos = mo.end() ++ ++class MacroDefinition(collections.namedtuple('MacroDefinition', ++ 'name_token args body error')): ++ """A preprocessor macro definition. ++ ++ name_token is the Token_ for the name. ++ ++ args is None for a macro that is not function-like. Otherwise, it ++ is a tuple that contains the macro argument name tokens. ++ ++ body is a tuple that contains the tokens that constitue the body ++ of the macro definition (excluding whitespace). ++ ++ error is None if no error was detected, or otherwise a problem ++ description associated with this macro definition. ++ ++ """ ++ ++ @property ++ def function(self): ++ """Return true if the macro is function-like.""" ++ return self.args is not None ++ ++ @property ++ def name(self): ++ """Return the name of the macro being defined.""" ++ return self.name_token.text ++ ++ @property ++ def line(self): ++ """Return the line number of the macro defintion.""" ++ return self.name_token.line ++ ++ @property ++ def args_lowered(self): ++ """Return the macro argument list as a list of strings""" ++ if self.function: ++ return [token.text for token in self.args] ++ else: ++ return None ++ ++ @property ++ def body_lowered(self): ++ """Return the macro body as a list of strings.""" ++ return [token.text for token in self.body] ++ ++def macro_definitions(tokens): ++ """A generator for C macro definitions among tokens. ++ ++ The generator yields MacroDefinition objects. ++ ++ tokens must be iterable, yielding Token_ objects. ++ ++ """ ++ ++ macro_name = None ++ macro_start = False # Set to false after macro name and one otken. ++ macro_args = None # Set to a list during the macro argument sequence. ++ in_macro_args = False # True while processing macro identifier-list. ++ error = None ++ body = [] ++ ++ for token in tokens: ++ if token.context == 'define' and macro_name is None \ ++ and token.kind == 'IDENT': ++ # Starting up macro processing. ++ if macro_start: ++ # First identifier is the macro name. ++ macro_name = token ++ else: ++ # Next token is the name. ++ macro_start = True ++ continue ++ ++ if macro_name is None: ++ # Drop tokens not in macro definitions. ++ continue ++ ++ if token.context != 'define': ++ # End of the macro definition. ++ if in_macro_args and error is None: ++ error = 'macro definition ends in macro argument list' ++ yield MacroDefinition(macro_name, macro_args, tuple(body), error) ++ # No longer in a macro definition. ++ macro_name = None ++ macro_start = False ++ macro_args = None ++ in_macro_args = False ++ error = None ++ body.clear() ++ continue ++ ++ if macro_start: ++ # First token after the macro name. ++ macro_start = False ++ if token.kind == 'PUNCTUATOR' and token.text == '(': ++ macro_args = [] ++ in_macro_args = True ++ continue ++ ++ if in_macro_args: ++ if token.kind == 'IDENT' \ ++ or (token.kind == 'PUNCTUATOR' and token.text == '...'): ++ # Macro argument or ... placeholder. ++ macro_args.append(token) ++ if token.kind == 'PUNCTUATOR': ++ if token.text == ')': ++ macro_args = tuple(macro_args) ++ in_macro_args = False ++ elif token.text == ',': ++ pass # Skip. Not a full syntax check. ++ elif error is None: ++ error = 'invalid punctuator in macro argument list: ' \ ++ + repr(token.text) ++ elif error is None: ++ error = 'invalid {} token in macro argument list'.format( ++ token.kind) ++ continue ++ ++ if token.kind not in ('WHITESPACE', 'BLOCK_COMMENT'): ++ body.append(token) ++ ++ # Emit the macro in case the last line does not end with a newline. ++ if macro_name is not None: ++ if in_macro_args and error is None: ++ error = 'macro definition ends in macro argument list' ++ yield MacroDefinition(macro_name, macro_args, tuple(body), error) ++ ++# Used to split UL etc. suffixes from numbers such as 123UL. ++RE_SPLIT_INTEGER_SUFFIX = re.compile(r'([^ullULL]+)([ullULL]*)') ++ ++BINARY_OPERATORS = { ++ '+': operator.add, ++ '<<': operator.lshift, ++} ++ ++# Use the general-purpose dict type if it is order-preserving. ++if (sys.version_info[0], sys.version_info[1]) <= (3, 6): ++ OrderedDict = collections.OrderedDict ++else: ++ OrderedDict = dict ++ ++def macro_eval(macro_defs, reporter): ++ """Compute macro values ++ ++ macro_defs is the output from macro_definitions. reporter is an ++ object that accepts reporter.error(line_number, message) and ++ reporter.note(line_number, message) calls to report errors ++ and error context invocations. ++ ++ The returned dict contains the values of macros which are not ++ function-like, pairing their names with their computed values. ++ ++ The current implementation is incomplete. It is deliberately not ++ entirely faithful to C, even in the implemented parts. It checks ++ that macro replacements follow certain syntactic rules even if ++ they are never evaluated. ++ ++ """ ++ ++ # Unevaluated macro definitions by name. ++ definitions = OrderedDict() ++ for md in macro_defs: ++ if md.name in definitions: ++ reporter.error(md.line, 'macro {} redefined'.format(md.name)) ++ reporter.note(definitions[md.name].line, ++ 'location of previous definition') ++ else: ++ definitions[md.name] = md ++ ++ # String to value mappings for fully evaluated macros. ++ evaluated = OrderedDict() ++ ++ # String to macro definitions during evaluation. Nice error ++ # reporting relies on determinstic iteration order. ++ stack = OrderedDict() ++ ++ def eval_token(current, token): ++ """Evaluate one macro token. ++ ++ Integers and strings are returned as such (the latter still ++ quoted). Identifiers are expanded. ++ ++ None indicates an empty expansion or an error. ++ ++ """ ++ ++ if token.kind == 'PP_NUMBER': ++ value = None ++ m = RE_SPLIT_INTEGER_SUFFIX.match(token.text) ++ if m: ++ try: ++ value = int(m.group(1), 0) ++ except ValueError: ++ pass ++ if value is None: ++ reporter.error(token.line, ++ 'invalid number {!r} in definition of {}'.format( ++ token.text, current.name)) ++ return value ++ ++ if token.kind == 'STRING': ++ return token.text ++ ++ if token.kind == 'CHARCONST' and len(token.text) == 3: ++ return ord(token.text[1]) ++ ++ if token.kind == 'IDENT': ++ name = token.text ++ result = eval1(current, name) ++ if name not in evaluated: ++ evaluated[name] = result ++ return result ++ ++ reporter.error(token.line, ++ 'unrecognized {!r} in definition of {}'.format( ++ token.text, current.name)) ++ return None ++ ++ ++ def eval1(current, name): ++ """Evaluate one name. ++ ++ The name is looked up and the macro definition evaluated ++ recursively if necessary. The current argument is the macro ++ definition being evaluated. ++ ++ None as a return value indicates an error. ++ ++ """ ++ ++ # Fast path if the value has already been evaluated. ++ if name in evaluated: ++ return evaluated[name] ++ ++ try: ++ md = definitions[name] ++ except KeyError: ++ reporter.error(current.line, ++ 'reference to undefined identifier {} in definition of {}' ++ .format(name, current.name)) ++ return None ++ ++ if md.name in stack: ++ # Recursive macro definition. ++ md = stack[name] ++ reporter.error(md.line, ++ 'macro definition {} refers to itself'.format(md.name)) ++ for md1 in reversed(list(stack.values())): ++ if md1 is md: ++ break ++ reporter.note(md1.line, ++ 'evaluated from {}'.format(md1.name)) ++ return None ++ ++ stack[md.name] = md ++ if md.function: ++ reporter.error(current.line, ++ 'attempt to evaluate function-like macro {}'.format(name)) ++ reporter.note(md.line, 'definition of {}'.format(md.name)) ++ return None ++ ++ try: ++ body = md.body ++ if len(body) == 0: ++ # Empty expansion. ++ return None ++ ++ # Remove surrounding (). ++ if body[0].text == '(' and body[-1].text == ')': ++ body = body[1:-1] ++ had_parens = True ++ else: ++ had_parens = False ++ ++ if len(body) == 1: ++ return eval_token(md, body[0]) ++ ++ # Minimal expression evaluator for binary operators. ++ op = body[1].text ++ if len(body) == 3 and op in BINARY_OPERATORS: ++ if not had_parens: ++ reporter.error(body[1].line, ++ 'missing parentheses around {} expression'.format(op)) ++ reporter.note(md.line, ++ 'in definition of macro {}'.format(md.name)) ++ ++ left = eval_token(md, body[0]) ++ right = eval_token(md, body[2]) ++ ++ if type(left) != type(1): ++ reporter.error(left.line, ++ 'left operand of {} is not an integer'.format(op)) ++ reporter.note(md.line, ++ 'in definition of macro {}'.format(md.name)) ++ if type(right) != type(1): ++ reporter.error(left.line, ++ 'right operand of {} is not an integer'.format(op)) ++ reporter.note(md.line, ++ 'in definition of macro {}'.format(md.name)) ++ return BINARY_OPERATORS[op](left, right) ++ ++ reporter.error(md.line, ++ 'uninterpretable macro token sequence: {}'.format( ++ ' '.join(md.body_lowered))) ++ return None ++ finally: ++ del stack[md.name] ++ ++ # Start of main body of macro_eval. ++ for md in definitions.values(): ++ name = md.name ++ if name not in evaluated and not md.function: ++ evaluated[name] = eval1(md, name) ++ return evaluated +diff --git a/support/Makefile b/support/Makefile +index 09b41b0d57e9239a..7749ac24f1ac3622 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -223,11 +223,11 @@ $(objpfx)true-container : $(libsupport) + tests = \ + README-testing \ + tst-support-namespace \ ++ tst-support-process_state \ + tst-support_blob_repeat \ + tst-support_capture_subprocess \ + tst-support_descriptors \ + tst-support_format_dns_packet \ +- tst-support-process_state \ + tst-support_quote_blob \ + tst-support_quote_string \ + tst-support_record_failure \ +@@ -248,6 +248,12 @@ $(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \ + $(evaluate-test) + endif + ++tests-special += $(objpfx)tst-glibcpp.out ++ ++$(objpfx)tst-glibcpp.out: tst-glibcpp.py $(..)scripts/glibcpp.py ++ PYTHONPATH=$(..)scripts $(PYTHON) tst-glibcpp.py > $@ 2>&1; \ ++ $(evaluate-test) ++ + $(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so + + tst-support_capture_subprocess-ARGS = -- $(host-test-program-cmd) +diff --git a/support/tst-glibcpp.py b/support/tst-glibcpp.py +new file mode 100644 +index 0000000000000000..a2db1916ccfce3c3 +--- /dev/null ++++ b/support/tst-glibcpp.py +@@ -0,0 +1,217 @@ ++#! /usr/bin/python3 ++# Tests for scripts/glibcpp.py ++# 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 ++# . ++ ++import inspect ++import sys ++ ++import glibcpp ++ ++# Error counter. ++errors = 0 ++ ++class TokenizerErrors: ++ """Used as the error reporter during tokenization.""" ++ ++ def __init__(self): ++ self.errors = [] ++ ++ def error(self, token, message): ++ self.errors.append((token, message)) ++ ++def check_macro_definitions(source, expected): ++ reporter = TokenizerErrors() ++ tokens = glibcpp.tokenize_c(source, reporter) ++ ++ actual = [] ++ for md in glibcpp.macro_definitions(tokens): ++ if md.function: ++ md_name = '{}({})'.format(md.name, ','.join(md.args_lowered)) ++ else: ++ md_name = md.name ++ actual.append((md_name, md.body_lowered)) ++ ++ if actual != expected or reporter.errors: ++ global errors ++ errors += 1 ++ # Obtain python source line information. ++ frame = inspect.stack(2)[1] ++ print('{}:{}: error: macro definition mismatch, actual definitions:' ++ .format(frame[1], frame[2])) ++ for md in actual: ++ print('note: {} {!r}'.format(md[0], md[1])) ++ ++ if reporter.errors: ++ for err in reporter.errors: ++ print('note: tokenizer error: {}: {}'.format( ++ err[0].line, err[1])) ++ ++def check_macro_eval(source, expected, expected_errors=''): ++ reporter = TokenizerErrors() ++ tokens = list(glibcpp.tokenize_c(source, reporter)) ++ ++ if reporter.errors: ++ # Obtain python source line information. ++ frame = inspect.stack(2)[1] ++ for err in reporter.errors: ++ print('{}:{}: tokenizer error: {}: {}'.format( ++ frame[1], frame[2], err[0].line, err[1])) ++ return ++ ++ class EvalReporter: ++ """Used as the error reporter during evaluation.""" ++ ++ def __init__(self): ++ self.lines = [] ++ ++ def error(self, line, message): ++ self.lines.append('{}: error: {}\n'.format(line, message)) ++ ++ def note(self, line, message): ++ self.lines.append('{}: note: {}\n'.format(line, message)) ++ ++ reporter = EvalReporter() ++ actual = glibcpp.macro_eval(glibcpp.macro_definitions(tokens), reporter) ++ actual_errors = ''.join(reporter.lines) ++ if actual != expected or actual_errors != expected_errors: ++ global errors ++ errors += 1 ++ # Obtain python source line information. ++ frame = inspect.stack(2)[1] ++ print('{}:{}: error: macro evaluation mismatch, actual results:' ++ .format(frame[1], frame[2])) ++ for k, v in actual.items(): ++ print(' {}: {!r}'.format(k, v)) ++ for msg in reporter.lines: ++ sys.stdout.write(' | ' + msg) ++ ++# Individual test cases follow. ++ ++check_macro_definitions('', []) ++check_macro_definitions('int main()\n{\n{\n', []) ++check_macro_definitions(""" ++#define A 1 ++#define B 2 /* ignored */ ++#define C 3 // also ignored ++#define D \ ++ 4 ++#define STRING "string" ++#define FUNCLIKE(a, b) (a + b) ++#define FUNCLIKE2(a, b) (a + \ ++ b) ++""", [('A', ['1']), ++ ('B', ['2']), ++ ('C', ['3']), ++ ('D', ['4']), ++ ('STRING', ['"string"']), ++ ('FUNCLIKE(a,b)', list('(a+b)')), ++ ('FUNCLIKE2(a,b)', list('(a+b)')), ++ ]) ++check_macro_definitions('#define MACRO', [('MACRO', [])]) ++check_macro_definitions('#define MACRO\n', [('MACRO', [])]) ++check_macro_definitions('#define MACRO()', [('MACRO()', [])]) ++check_macro_definitions('#define MACRO()\n', [('MACRO()', [])]) ++ ++check_macro_eval('#define A 1', {'A': 1}) ++check_macro_eval('#define A (1)', {'A': 1}) ++check_macro_eval('#define A (1 + 1)', {'A': 2}) ++check_macro_eval('#define A (1U << 31)', {'A': 1 << 31}) ++check_macro_eval('''\ ++#define A (B + 1) ++#define B 10 ++#define F(x) ignored ++#define C "not ignored" ++''', { ++ 'A': 11, ++ 'B': 10, ++ 'C': '"not ignored"', ++}) ++ ++# Checking for evaluation errors. ++check_macro_eval('''\ ++#define A 1 ++#define A 2 ++''', { ++ 'A': 1, ++}, '''\ ++2: error: macro A redefined ++1: note: location of previous definition ++''') ++ ++check_macro_eval('''\ ++#define A A ++#define B 1 ++''', { ++ 'A': None, ++ 'B': 1, ++}, '''\ ++1: error: macro definition A refers to itself ++''') ++ ++check_macro_eval('''\ ++#define A B ++#define B A ++''', { ++ 'A': None, ++ 'B': None, ++}, '''\ ++1: error: macro definition A refers to itself ++2: note: evaluated from B ++''') ++ ++check_macro_eval('''\ ++#define A B ++#define B C ++#define C A ++''', { ++ 'A': None, ++ 'B': None, ++ 'C': None, ++}, '''\ ++1: error: macro definition A refers to itself ++3: note: evaluated from C ++2: note: evaluated from B ++''') ++ ++check_macro_eval('''\ ++#define A 1 + ++''', { ++ 'A': None, ++}, '''\ ++1: error: uninterpretable macro token sequence: 1 + ++''') ++ ++check_macro_eval('''\ ++#define A 3*5 ++''', { ++ 'A': None, ++}, '''\ ++1: error: uninterpretable macro token sequence: 3 * 5 ++''') ++ ++check_macro_eval('''\ ++#define A 3 + 5 ++''', { ++ 'A': 8, ++}, '''\ ++1: error: missing parentheses around + expression ++1: note: in definition of macro A ++''') ++ ++if errors: ++ sys.exit(1) diff --git a/glibc-rh2109510-2.patch b/glibc-rh2109510-2.patch new file mode 100644 index 0000000..3aba395 --- /dev/null +++ b/glibc-rh2109510-2.patch @@ -0,0 +1,208 @@ +Partial backport of: + +commit 7e1d42400c1b8f03316fe14176133c8853cd3bbe +Author: Joseph Myers +Date: Fri Nov 30 15:20:41 2018 +0000 + + Replace gen-as-const.awk by gen-as-const.py. + + This patch replaces gen-as-const.awk, and some fragments of the + Makefile code that used it, by a Python script. The point is not such + much that awk is problematic for this particular script, as that I'd + like to build up a general Python infrastructure for extracting + information from C headers, for use in writing tests of such headers. + Thus, although this patch does not set up such infrastructure, the + compute_c_consts function in gen-as-const.py might be moved to a + separate Python module in a subsequent patch as a starting point for + such infrastructure. + + The general idea of the code is the same as in the awk version, but no + attempt is made to make the output files textually identical. When + generating a header, a dict of constant names and values is generated + internally then defines are printed in sorted order (rather than the + order in the .sym file, which would have been used before). When + generating a test that the values computed match those from a normal + header inclusion, the test code is made into a compilation test using + _Static_assert, where previously the comparisons were done only when + the test was executed. One fragment of test generation (converting + the previously generated header to use asconst_* prefixes on its macro + names) is still in awk code in the makefiles; only the .sym processing + and subsequent execution of the compiler to extract constants have + moved to the Python script. + + Tested for x86_64, and with build-many-glibcs.py. + + * scripts/gen-as-const.py: New file. + * scripts/gen-as-const.awk: Remove. + * Makerules ($(common-objpfx)%.h $(common-objpfx)%.h.d): Use + gen-as-const.py. + ($(objpfx)test-as-const-%.c): Likewise. + +In the downstream version, scripts/gen-as-const.awk is not removed and +still used in Makerules. + +diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py +new file mode 100644 +index 0000000000000000..b7a5744bb192dd67 +--- /dev/null ++++ b/scripts/gen-as-const.py +@@ -0,0 +1,159 @@ ++#!/usr/bin/python3 ++# Produce headers of assembly constants from C expressions. ++# Copyright (C) 2018 Free Software Foundation, Inc. ++# This file is part of the GNU C Library. ++# ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++# ++# The GNU C Library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# . ++ ++# The input to this script looks like: ++# #cpp-directive ... ++# NAME1 ++# NAME2 expression ... ++# A line giving just a name implies an expression consisting of just that name. ++ ++import argparse ++import os.path ++import re ++import subprocess ++import tempfile ++ ++ ++def compute_c_consts(sym_data, cc): ++ """Compute the values of some C constants. ++ ++ The first argument is a list whose elements are either strings ++ (preprocessor directives) or pairs of strings (a name and a C ++ expression for the corresponding value). Preprocessor directives ++ in the middle of the list may be used to select which constants ++ end up being evaluated using which expressions. ++ ++ """ ++ out_lines = [] ++ started = False ++ for arg in sym_data: ++ if isinstance(arg, str): ++ out_lines.append(arg) ++ continue ++ name = arg[0] ++ value = arg[1] ++ if not started: ++ out_lines.append('void\ndummy (void)\n{') ++ started = True ++ out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" ' ++ ': : \"i\" ((long int) (%s)));' ++ % (name, value)) ++ if started: ++ out_lines.append('}') ++ out_lines.append('') ++ out_text = '\n'.join(out_lines) ++ with tempfile.TemporaryDirectory() as temp_dir: ++ c_file_name = os.path.join(temp_dir, 'test.c') ++ s_file_name = os.path.join(temp_dir, 'test.s') ++ with open(c_file_name, 'w') as c_file: ++ c_file.write(out_text) ++ # Compilation has to be from stdin to avoid the temporary file ++ # name being written into the generated dependencies. ++ cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name)) ++ subprocess.check_call(cmd, shell=True) ++ consts = {} ++ with open(s_file_name, 'r') as s_file: ++ for line in s_file: ++ match = re.search('@@@name@@@([^@]*)' ++ '@@@value@@@[^0-9Xxa-fA-F-]*' ++ '([0-9Xxa-fA-F-]+).*@@@end@@@', line) ++ if match: ++ if (match.group(1) in consts ++ and match.group(2) != consts[match.group(1)]): ++ raise ValueError('duplicate constant %s' ++ % match.group(1)) ++ consts[match.group(1)] = match.group(2) ++ return consts ++ ++ ++def gen_test(sym_data): ++ """Generate a test for the values of some C constants. ++ ++ The first argument is as for compute_c_consts. ++ ++ """ ++ out_lines = [] ++ started = False ++ for arg in sym_data: ++ if isinstance(arg, str): ++ out_lines.append(arg) ++ continue ++ name = arg[0] ++ value = arg[1] ++ if not started: ++ out_lines.append('#include \n' ++ '#include \n' ++ '#include \n' ++ '#if __WORDSIZE == 64\n' ++ 'typedef uint64_t c_t;\n' ++ '# define U(n) UINT64_C (n)\n' ++ '#else\n' ++ 'typedef uint32_t c_t;\n' ++ '# define U(n) UINT32_C (n)\n' ++ '#endif\n' ++ 'static int\n' ++ 'do_test (void)\n' ++ '{\n' ++ # Compilation test only, using static assertions. ++ ' return 0;\n' ++ '}\n' ++ '#include ') ++ started = True ++ out_lines.append('_Static_assert (U (asconst_%s) == (c_t) (%s), ' ++ '"value of %s");' ++ % (name, value, name)) ++ return '\n'.join(out_lines) ++ ++ ++def main(): ++ """The main entry point.""" ++ parser = argparse.ArgumentParser( ++ description='Produce headers of assembly constants.') ++ parser.add_argument('--cc', metavar='CC', ++ help='C compiler (including options) to use') ++ parser.add_argument('--test', action='store_true', ++ help='Generate test case instead of header') ++ parser.add_argument('sym_file', ++ help='.sym file to process') ++ args = parser.parse_args() ++ sym_data = [] ++ with open(args.sym_file, 'r') as sym_file: ++ for line in sym_file: ++ line = line.strip() ++ if line == '': ++ continue ++ # Pass preprocessor directives through. ++ if line.startswith('#'): ++ sym_data.append(line) ++ continue ++ words = line.split(maxsplit=1) ++ # Separator. ++ if words[0] == '--': ++ continue ++ name = words[0] ++ value = words[1] if len(words) > 1 else words[0] ++ sym_data.append((name, value)) ++ if args.test: ++ print(gen_test(sym_data)) ++ else: ++ consts = compute_c_consts(sym_data, args.cc) ++ print('\n'.join('#define %s %s' % c for c in sorted(consts.items()))) ++ ++if __name__ == '__main__': ++ main() diff --git a/glibc-rh2109510-20.patch b/glibc-rh2109510-20.patch new file mode 100644 index 0000000..1007e9d --- /dev/null +++ b/glibc-rh2109510-20.patch @@ -0,0 +1,36 @@ +commit 29eb7961197bee68470730aecfdda4d0e206812e +Author: Florian Weimer +Date: Mon Sep 5 12:11:19 2022 +0200 + + elf.h: Remove duplicate definition of VER_FLG_WEAK + + This did not cause a warning before because the token sequence for + the two definitions was identical. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/elf.h b/elf/elf.h +index d6506ea1c7160dea..ec09040be639a52a 100644 +--- a/elf/elf.h ++++ b/elf/elf.h +@@ -1027,7 +1027,8 @@ typedef struct + + /* Legal values for vd_flags (version information flags). */ + #define VER_FLG_BASE 0x1 /* Version definition of file itself */ +-#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier. Also ++ used by vna_flags below. */ + + /* Versym symbol index values. */ + #define VER_NDX_LOCAL 0 /* Symbol is local. */ +@@ -1105,10 +1106,6 @@ typedef struct + } Elf64_Vernaux; + + +-/* Legal values for vna_flags. */ +-#define VER_FLG_WEAK 0x2 /* Weak version identifier */ +- +- + /* Auxiliary vector. */ + + /* This vector is normally only used by the program interpreter. The diff --git a/glibc-rh2109510-21.patch b/glibc-rh2109510-21.patch new file mode 100644 index 0000000..5e58123 --- /dev/null +++ b/glibc-rh2109510-21.patch @@ -0,0 +1,1295 @@ +commit 340097d0b50eff9d3058e06c6989ae398c653d4a +Author: Florian Weimer +Date: Thu Sep 22 12:10:41 2022 +0200 + + elf: Extract glibcelf constants from + + The need to maintain elf/elf.h and scripts/glibcelf.py in parallel + results in a backporting hazard: they need to be kept in sync to + avoid elf/tst-glibcelf consistency check failures. glibcelf (unlike + tst-glibcelf) does not use the C implementation to extract constants. + This applies the additional glibcpp syntax checks to . + + This changereplaces the types derived from Python enum types with + custom types _TypedConstant, _IntConstant, and _FlagConstant. These + types have fewer safeguards, but this also allows incremental + construction and greater flexibility for grouping constants among + the types. Architectures-specific named constants are now added + as members into their superclasses (but value-based lookup is + still restricted to generic constants only). + + Consequently, check_duplicates in elf/tst-glibcelf has been adjusted + to accept differently-named constants of the same value if their + subtypes are distinct. The ordering check for named constants + has been dropped because they are no longer strictly ordered. + + Further test adjustments: Some of the type names are different. + The new types do not support iteration (because it is unclear + whether iteration should cover the all named values (including + architecture-specific constants), or only the generic named values), + so elf/tst-glibcelf now uses by_name explicit (to get all constants). + PF_HP_SBP and PF_PARISC_SBP are now of distinct types (PfHP and + PfPARISC), so they are how both present on the Python side. EM_NUM + and PT_NUM are filtered (which was an oversight in the old + conversion). + + The new version of glibcelf should also be compatible with earlier + Python versions because it no longer depends on the enum module and its + advanced features. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py +index e5026e2289df206b..a5bff45eae55edea 100644 +--- a/elf/tst-glibcelf.py ++++ b/elf/tst-glibcelf.py +@@ -18,7 +18,6 @@ + # . + + import argparse +-import enum + import sys + + import glibcelf +@@ -45,11 +44,57 @@ def find_constant_prefix(name): + + def find_enum_types(): + """A generator for OpenIntEnum and IntFlag classes in glibcelf.""" ++ classes = set((glibcelf._TypedConstant, glibcelf._IntConstant, ++ glibcelf._FlagConstant)) + for obj in vars(glibcelf).values(): +- if isinstance(obj, type) and obj.__bases__[0] in ( +- glibcelf._OpenIntEnum, enum.Enum, enum.IntFlag): ++ if isinstance(obj, type) and obj not in classes \ ++ and obj.__bases__[0] in classes: + yield obj + ++def check_basic(): ++ """Check basic functionality of the constant classes.""" ++ ++ if glibcelf.Pt.PT_NULL is not glibcelf.Pt(0): ++ error('Pt(0) not interned') ++ if glibcelf.Pt(17609) is glibcelf.Pt(17609): ++ error('Pt(17609) unexpectedly interned') ++ if glibcelf.Pt(17609) == glibcelf.Pt(17609): ++ pass ++ else: ++ error('Pt(17609) equality') ++ if glibcelf.Pt(17610) == glibcelf.Pt(17609): ++ error('Pt(17610) equality') ++ ++ if str(glibcelf.Pt.PT_NULL) != 'PT_NULL': ++ error('str(PT_NULL)') ++ if str(glibcelf.Pt(17609)) != '17609': ++ error('str(Pt(17609))') ++ ++ if repr(glibcelf.Pt.PT_NULL) != 'PT_NULL': ++ error('repr(PT_NULL)') ++ if repr(glibcelf.Pt(17609)) != 'Pt(17609)': ++ error('repr(Pt(17609))') ++ ++ if glibcelf.Pt('PT_AARCH64_MEMTAG_MTE') \ ++ is not glibcelf.Pt.PT_AARCH64_MEMTAG_MTE: ++ error('PT_AARCH64_MEMTAG_MTE identity') ++ if glibcelf.Pt(0x70000002) is glibcelf.Pt.PT_AARCH64_MEMTAG_MTE: ++ error('Pt(0x70000002) identity') ++ if glibcelf.PtAARCH64(0x70000002) is not glibcelf.Pt.PT_AARCH64_MEMTAG_MTE: ++ error('PtAARCH64(0x70000002) identity') ++ if glibcelf.Pt.PT_AARCH64_MEMTAG_MTE.short_name != 'AARCH64_MEMTAG_MTE': ++ error('PT_AARCH64_MEMTAG_MTE short name') ++ ++ # Special cases for int-like Shn. ++ if glibcelf.Shn(32) == glibcelf.Shn.SHN_XINDEX: ++ error('Shn(32)') ++ if glibcelf.Shn(32) + 0 != 32: ++ error('Shn(32) + 0') ++ if 32 in glibcelf.Shn: ++ error('32 in Shn') ++ if 0 not in glibcelf.Shn: ++ error('0 not in Shn') ++ + def check_duplicates(): + """Verifies that enum types do not have duplicate values. + +@@ -59,17 +104,16 @@ def check_duplicates(): + global_seen = {} + for typ in find_enum_types(): + seen = {} +- last = None +- for (name, e) in typ.__members__.items(): ++ for (name, e) in typ.by_name.items(): + if e.value in seen: +- error('{} has {}={} and {}={}'.format( +- typ, seen[e.value], e.value, name, e.value)) +- last = e ++ other = seen[e.value] ++ # Value conflicts only count if they are between ++ # the same base type. ++ if e.__class__ is typ and other.__class__ is typ: ++ error('{} has {}={} and {}={}'.format( ++ typ, other, e.value, name, e.value)) + else: + seen[e.value] = name +- if last is not None and last.value > e.value: +- error('{} has {}={} after {}={}'.format( +- typ, name, e.value, last.name, last.value)) + if name in global_seen: + error('{} used in {} and {}'.format( + name, global_seen[name], typ)) +@@ -81,7 +125,7 @@ def check_constant_prefixes(): + seen = set() + for typ in find_enum_types(): + typ_prefix = None +- for val in typ: ++ for val in typ.by_name.values(): + prefix = find_constant_prefix(val.name) + if prefix is None: + error('constant {!r} for {} has unknown prefix'.format( +@@ -113,7 +157,6 @@ def find_elf_h_constants(cc): + # used in . + glibcelf_skipped_aliases = ( + ('EM_ARC_A5', 'EM_ARC_COMPACT'), +- ('PF_PARISC_SBP', 'PF_HP_SBP') + ) + + # Constants that provide little value and are not included in +@@ -146,6 +189,7 @@ DT_VALRNGLO + DT_VERSIONTAGNUM + ELFCLASSNUM + ELFDATANUM ++EM_NUM + ET_HIOS + ET_HIPROC + ET_LOOS +@@ -159,6 +203,7 @@ PT_HISUNW + PT_LOOS + PT_LOPROC + PT_LOSUNW ++PT_NUM + SHF_MASKOS + SHF_MASKPROC + SHN_HIOS +@@ -193,7 +238,7 @@ def check_constant_values(cc): + """Checks the values of constants against glibcelf.""" + + glibcelf_constants = { +- e.name: e for typ in find_enum_types() for e in typ} ++ e.name: e for typ in find_enum_types() for e in typ.by_name.values()} + elf_h_constants = find_elf_h_constants(cc=cc) + + missing_in_glibcelf = (set(elf_h_constants) - set(glibcelf_constants) +@@ -229,12 +274,13 @@ def check_constant_values(cc): + for name in sorted(set(glibcelf_constants) & set(elf_h_constants)): + glibcelf_value = glibcelf_constants[name].value + elf_h_value = int(elf_h_constants[name]) +- # On 32-bit architectures as some constants that are ++ # On 32-bit architectures has some constants that are + # parsed as signed, while they are unsigned in glibcelf. So + # far, this only affects some flag constants, so special-case + # them here. + if (glibcelf_value != elf_h_value +- and not (isinstance(glibcelf_constants[name], enum.IntFlag) ++ and not (isinstance(glibcelf_constants[name], ++ glibcelf._FlagConstant) + and glibcelf_value == 1 << 31 + and elf_h_value == -(1 << 31))): + error('{}: glibcelf has {!r}, has {!r}'.format( +@@ -266,6 +312,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + ++ check_basic() + check_duplicates() + check_constant_prefixes() + check_constant_values(cc=args.cc) +diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py +index 5c8f46f590722384..420cb21943b28bba 100644 +--- a/scripts/glibcelf.py ++++ b/scripts/glibcelf.py +@@ -25,711 +25,445 @@ parsing it. + """ + + import collections +-import enum ++import functools ++import os + import struct + +-if not hasattr(enum, 'IntFlag'): +- import sys +- sys.stdout.write( +- 'warning: glibcelf.py needs Python 3.6 for enum support\n') +- sys.exit(77) ++import glibcpp ++ ++class _MetaNamedValue(type): ++ """Used to set up _NamedValue subclasses.""" + +-class _OpenIntEnum(enum.IntEnum): +- """Integer enumeration that supports arbitrary int values.""" + @classmethod +- def _missing_(cls, value): +- # See enum.IntFlag._create_pseudo_member_. This allows +- # creating of enum constants with arbitrary integer values. +- pseudo_member = int.__new__(cls, value) +- pseudo_member._name_ = None +- pseudo_member._value_ = value +- return pseudo_member ++ def __prepare__(metacls, cls, bases, **kwds): ++ # Indicates an int-based class. Needed for types like Shn. ++ int_based = False ++ for base in bases: ++ if issubclass(base, int): ++ int_based = int ++ break ++ return dict(by_value={}, ++ by_name={}, ++ prefix=None, ++ _int_based=int_based) + +- def __repr__(self): +- name = self._name_ +- if name is not None: +- # The names have prefixes like SHT_, implying their type. +- return name +- return '{}({})'.format(self.__class__.__name__, self._value_) ++ def __contains__(self, other): ++ return other in self.by_value ++ ++class _NamedValue(metaclass=_MetaNamedValue): ++ """Typed, named integer constants. ++ ++ Constants have the following instance attributes: ++ ++ name: The full name of the constant (e.g., "PT_NULL"). ++ short_name: The name with of the constant without the prefix ("NULL"). ++ value: The integer value of the constant. ++ ++ The following class attributes are available: ++ ++ by_value: A dict mapping integers to constants. ++ by_name: A dict mapping strings to constants. ++ prefix: A string that is removed from the start of short names, or None. ++ ++ """ ++ ++ def __new__(cls, arg0, arg1=None): ++ """Instance creation. ++ ++ For the one-argument form, the argument must be a string, an ++ int, or an instance of this class. Strings are looked up via ++ by_name. Values are looked up via by_value; if value lookup ++ fails, a new unnamed instance is returned. Instances of this ++ class a re returned as-is. ++ ++ The two-argument form expects the name (a string) and the ++ value (an integer). A new instance is created in this case. ++ The instance is not registered in the by_value/by_name ++ dictionaries (but the caller can do that). ++ ++ """ ++ ++ typ0 = type(arg0) ++ if arg1 is None: ++ if isinstance(typ0, cls): ++ # Re-use the existing object. ++ return arg0 ++ if typ0 is int: ++ by_value = cls.by_value ++ try: ++ return by_value[arg0] ++ except KeyError: ++ # Create a new object of the requested value. ++ if cls._int_based: ++ result = int.__new__(cls, arg0) ++ else: ++ result = object.__new__(cls) ++ result.value = arg0 ++ result.name = None ++ return result ++ if typ0 is str: ++ by_name = cls.by_name ++ try: ++ return by_name[arg0] ++ except KeyError: ++ raise ValueError('unknown {} constant: {!r}'.format( ++ cls.__name__, arg0)) ++ else: ++ # Types for the two-argument form are rigid. ++ if typ0 is not str and typ0 is not None: ++ raise ValueError('type {} of name {!r} should be str'.format( ++ typ0.__name__, arg0)) ++ if type(arg1) is not int: ++ raise ValueError('type {} of value {!r} should be int'.format( ++ type(arg1).__name__, arg1)) ++ # Create a new named constants. ++ if cls._int_based: ++ result = int.__new__(cls, arg1) ++ else: ++ result = object.__new__(cls) ++ result.value = arg1 ++ result.name = arg0 ++ # Set up the short_name attribute. ++ prefix = cls.prefix ++ if prefix and arg0.startswith(prefix): ++ result.short_name = arg0[len(prefix):] ++ else: ++ result.short_name = arg0 ++ return result + + def __str__(self): +- name = self._name_ +- if name is not None: ++ name = self.name ++ if name: ++ return name ++ else: ++ return str(self.value) ++ ++ def __repr__(self): ++ name = self.name ++ if name: + return name +- return str(self._value_) ++ else: ++ return '{}({})'.format(self.__class__.__name__, self.value) ++ ++ def __setattr__(self, name, value): ++ # Prevent modification of the critical attributes once they ++ # have been set. ++ if name in ('name', 'value', 'short_name') and hasattr(self, name): ++ raise AttributeError('can\'t set attribute {}'.format(name)) ++ object.__setattr__(self, name, value) ++ ++@functools.total_ordering ++class _TypedConstant(_NamedValue): ++ """Base class for integer-valued optionally named constants. ++ ++ This type is not an integer type. ++ ++ """ ++ ++ def __eq__(self, other): ++ return isinstance(other, self.__class__) and self.value == other.value ++ ++ def __lt__(self, other): ++ return isinstance(other, self.__class__) and self.value <= other.value ++ ++ def __hash__(self): ++ return hash(self.value) ++ ++class _IntConstant(_NamedValue, int): ++ """Base class for integer-like optionally named constants. ++ ++ Instances compare equal to the integer of the same value, and can ++ be used in integer arithmetic. ++ ++ """ + +-class ElfClass(_OpenIntEnum): ++ pass ++ ++class _FlagConstant(_TypedConstant, int): ++ pass ++ ++def _parse_elf_h(): ++ """Read ../elf/elf.h and return a dict with the constants in it.""" ++ ++ path = os.path.join(os.path.dirname(os.path.realpath(__file__)), ++ '..', 'elf', 'elf.h') ++ class TokenizerReporter: ++ """Report tokenizer errors to standard output.""" ++ ++ def __init__(self): ++ self.errors = 0 ++ ++ def error(self, token, message): ++ self.errors += 1 ++ print('{}:{}:{}: error: {}'.format( ++ path, token.line, token.column, message)) ++ ++ reporter = TokenizerReporter() ++ with open(path) as inp: ++ tokens = glibcpp.tokenize_c(inp.read(), reporter) ++ if reporter.errors: ++ raise IOError('parse error in elf.h') ++ ++ class MacroReporter: ++ """Report macro errors to standard output.""" ++ ++ def __init__(self): ++ self.errors = 0 ++ ++ def error(self, line, message): ++ errors += 1 ++ print('{}:{}: error: {}'.format(path, line, message)) ++ ++ def note(self, line, message): ++ print('{}:{}: note: {}'.format(path, line, message)) ++ ++ reporter = MacroReporter() ++ result = glibcpp.macro_eval(glibcpp.macro_definitions(tokens), reporter) ++ if reporter.errors: ++ raise IOError('parse error in elf.h') ++ ++ return result ++_elf_h = _parse_elf_h() ++del _parse_elf_h ++_elf_h_processed = set() ++ ++def _register_elf_h(cls, prefix=None, skip=(), ranges=False, parent=None): ++ prefix = prefix or cls.prefix ++ if not prefix: ++ raise ValueError('missing prefix for {}'.format(cls.__name__)) ++ by_value = cls.by_value ++ by_name = cls.by_name ++ processed = _elf_h_processed ++ ++ skip = set(skip) ++ skip.add(prefix + 'NUM') ++ if ranges: ++ skip.add(prefix + 'LOOS') ++ skip.add(prefix + 'HIOS') ++ skip.add(prefix + 'LOPROC') ++ skip.add(prefix + 'HIPROC') ++ cls.os_range = (_elf_h[prefix + 'LOOS'], _elf_h[prefix + 'HIOS']) ++ cls.proc_range = (_elf_h[prefix + 'LOPROC'], _elf_h[prefix + 'HIPROC']) ++ ++ # Inherit the prefix from the parent if not set. ++ if parent and cls.prefix is None and parent.prefix is not None: ++ cls.prefix = parent.prefix ++ ++ processed_len_start = len(processed) ++ for name, value in _elf_h.items(): ++ if name in skip or name in processed: ++ continue ++ if name.startswith(prefix): ++ processed.add(name) ++ if value in by_value: ++ raise ValueError('duplicate value {}: {}, {}'.format( ++ value, name, by_value[value])) ++ obj = cls(name, value) ++ by_value[value] = obj ++ by_name[name] = obj ++ setattr(cls, name, obj) ++ if parent: ++ # Make the symbolic name available through the parent as well. ++ parent.by_name[name] = obj ++ setattr(parent, name, obj) ++ ++ if len(processed) == processed_len_start: ++ raise ValueError('nothing matched prefix {!r}'.format(prefix)) ++ ++class ElfClass(_TypedConstant): + """ELF word size. Type of EI_CLASS values.""" +- ELFCLASSNONE = 0 +- ELFCLASS32 = 1 +- ELFCLASS64 = 2 ++_register_elf_h(ElfClass, prefix='ELFCLASS') + +-class ElfData(_OpenIntEnum): ++class ElfData(_TypedConstant): + """ELF endianess. Type of EI_DATA values.""" +- ELFDATANONE = 0 +- ELFDATA2LSB = 1 +- ELFDATA2MSB = 2 ++_register_elf_h(ElfData, prefix='ELFDATA') + +-class Machine(_OpenIntEnum): ++class Machine(_TypedConstant): + """ELF machine type. Type of values in Ehdr.e_machine field.""" +- EM_NONE = 0 +- EM_M32 = 1 +- EM_SPARC = 2 +- EM_386 = 3 +- EM_68K = 4 +- EM_88K = 5 +- EM_IAMCU = 6 +- EM_860 = 7 +- EM_MIPS = 8 +- EM_S370 = 9 +- EM_MIPS_RS3_LE = 10 +- EM_PARISC = 15 +- EM_VPP500 = 17 +- EM_SPARC32PLUS = 18 +- EM_960 = 19 +- EM_PPC = 20 +- EM_PPC64 = 21 +- EM_S390 = 22 +- EM_SPU = 23 +- EM_V800 = 36 +- EM_FR20 = 37 +- EM_RH32 = 38 +- EM_RCE = 39 +- EM_ARM = 40 +- EM_FAKE_ALPHA = 41 +- EM_SH = 42 +- EM_SPARCV9 = 43 +- EM_TRICORE = 44 +- EM_ARC = 45 +- EM_H8_300 = 46 +- EM_H8_300H = 47 +- EM_H8S = 48 +- EM_H8_500 = 49 +- EM_IA_64 = 50 +- EM_MIPS_X = 51 +- EM_COLDFIRE = 52 +- EM_68HC12 = 53 +- EM_MMA = 54 +- EM_PCP = 55 +- EM_NCPU = 56 +- EM_NDR1 = 57 +- EM_STARCORE = 58 +- EM_ME16 = 59 +- EM_ST100 = 60 +- EM_TINYJ = 61 +- EM_X86_64 = 62 +- EM_PDSP = 63 +- EM_PDP10 = 64 +- EM_PDP11 = 65 +- EM_FX66 = 66 +- EM_ST9PLUS = 67 +- EM_ST7 = 68 +- EM_68HC16 = 69 +- EM_68HC11 = 70 +- EM_68HC08 = 71 +- EM_68HC05 = 72 +- EM_SVX = 73 +- EM_ST19 = 74 +- EM_VAX = 75 +- EM_CRIS = 76 +- EM_JAVELIN = 77 +- EM_FIREPATH = 78 +- EM_ZSP = 79 +- EM_MMIX = 80 +- EM_HUANY = 81 +- EM_PRISM = 82 +- EM_AVR = 83 +- EM_FR30 = 84 +- EM_D10V = 85 +- EM_D30V = 86 +- EM_V850 = 87 +- EM_M32R = 88 +- EM_MN10300 = 89 +- EM_MN10200 = 90 +- EM_PJ = 91 +- EM_OPENRISC = 92 +- EM_ARC_COMPACT = 93 +- EM_XTENSA = 94 +- EM_VIDEOCORE = 95 +- EM_TMM_GPP = 96 +- EM_NS32K = 97 +- EM_TPC = 98 +- EM_SNP1K = 99 +- EM_ST200 = 100 +- EM_IP2K = 101 +- EM_MAX = 102 +- EM_CR = 103 +- EM_F2MC16 = 104 +- EM_MSP430 = 105 +- EM_BLACKFIN = 106 +- EM_SE_C33 = 107 +- EM_SEP = 108 +- EM_ARCA = 109 +- EM_UNICORE = 110 +- EM_EXCESS = 111 +- EM_DXP = 112 +- EM_ALTERA_NIOS2 = 113 +- EM_CRX = 114 +- EM_XGATE = 115 +- EM_C166 = 116 +- EM_M16C = 117 +- EM_DSPIC30F = 118 +- EM_CE = 119 +- EM_M32C = 120 +- EM_TSK3000 = 131 +- EM_RS08 = 132 +- EM_SHARC = 133 +- EM_ECOG2 = 134 +- EM_SCORE7 = 135 +- EM_DSP24 = 136 +- EM_VIDEOCORE3 = 137 +- EM_LATTICEMICO32 = 138 +- EM_SE_C17 = 139 +- EM_TI_C6000 = 140 +- EM_TI_C2000 = 141 +- EM_TI_C5500 = 142 +- EM_TI_ARP32 = 143 +- EM_TI_PRU = 144 +- EM_MMDSP_PLUS = 160 +- EM_CYPRESS_M8C = 161 +- EM_R32C = 162 +- EM_TRIMEDIA = 163 +- EM_QDSP6 = 164 +- EM_8051 = 165 +- EM_STXP7X = 166 +- EM_NDS32 = 167 +- EM_ECOG1X = 168 +- EM_MAXQ30 = 169 +- EM_XIMO16 = 170 +- EM_MANIK = 171 +- EM_CRAYNV2 = 172 +- EM_RX = 173 +- EM_METAG = 174 +- EM_MCST_ELBRUS = 175 +- EM_ECOG16 = 176 +- EM_CR16 = 177 +- EM_ETPU = 178 +- EM_SLE9X = 179 +- EM_L10M = 180 +- EM_K10M = 181 +- EM_AARCH64 = 183 +- EM_AVR32 = 185 +- EM_STM8 = 186 +- EM_TILE64 = 187 +- EM_TILEPRO = 188 +- EM_MICROBLAZE = 189 +- EM_CUDA = 190 +- EM_TILEGX = 191 +- EM_CLOUDSHIELD = 192 +- EM_COREA_1ST = 193 +- EM_COREA_2ND = 194 +- EM_ARCV2 = 195 +- EM_OPEN8 = 196 +- EM_RL78 = 197 +- EM_VIDEOCORE5 = 198 +- EM_78KOR = 199 +- EM_56800EX = 200 +- EM_BA1 = 201 +- EM_BA2 = 202 +- EM_XCORE = 203 +- EM_MCHP_PIC = 204 +- EM_INTELGT = 205 +- EM_KM32 = 210 +- EM_KMX32 = 211 +- EM_EMX16 = 212 +- EM_EMX8 = 213 +- EM_KVARC = 214 +- EM_CDP = 215 +- EM_COGE = 216 +- EM_COOL = 217 +- EM_NORC = 218 +- EM_CSR_KALIMBA = 219 +- EM_Z80 = 220 +- EM_VISIUM = 221 +- EM_FT32 = 222 +- EM_MOXIE = 223 +- EM_AMDGPU = 224 +- EM_RISCV = 243 +- EM_BPF = 247 +- EM_CSKY = 252 +- EM_LOONGARCH = 258 +- EM_NUM = 259 +- EM_ALPHA = 0x9026 +- +-class Et(_OpenIntEnum): ++ prefix = 'EM_' ++_register_elf_h(Machine, skip=('EM_ARC_A5',)) ++ ++class Et(_TypedConstant): + """ELF file type. Type of ET_* values and the Ehdr.e_type field.""" +- ET_NONE = 0 +- ET_REL = 1 +- ET_EXEC = 2 +- ET_DYN = 3 +- ET_CORE = 4 ++ prefix = 'ET_' ++_register_elf_h(Et, ranges=True) + +-class Shn(_OpenIntEnum): ++class Shn(_IntConstant): + """ELF reserved section indices.""" +- SHN_UNDEF = 0 +- SHN_BEFORE = 0xff00 +- SHN_AFTER = 0xff01 +- SHN_ABS = 0xfff1 +- SHN_COMMON = 0xfff2 +- SHN_XINDEX = 0xffff +- +-class ShnMIPS(enum.Enum): ++ prefix = 'SHN_' ++class ShnMIPS(Shn): + """Supplemental SHN_* constants for EM_MIPS.""" +- SHN_MIPS_ACOMMON = 0xff00 +- SHN_MIPS_TEXT = 0xff01 +- SHN_MIPS_DATA = 0xff02 +- SHN_MIPS_SCOMMON = 0xff03 +- SHN_MIPS_SUNDEFINED = 0xff04 +- +-class ShnPARISC(enum.Enum): ++class ShnPARISC(Shn): + """Supplemental SHN_* constants for EM_PARISC.""" +- SHN_PARISC_ANSI_COMMON = 0xff00 +- SHN_PARISC_HUGE_COMMON = 0xff01 ++_register_elf_h(ShnMIPS, prefix='SHN_MIPS_', parent=Shn) ++_register_elf_h(ShnPARISC, prefix='SHN_PARISC_', parent=Shn) ++_register_elf_h(Shn, skip='SHN_LORESERVE SHN_HIRESERVE'.split(), ranges=True) + +-class Sht(_OpenIntEnum): ++class Sht(_TypedConstant): + """ELF section types. Type of SHT_* values.""" +- SHT_NULL = 0 +- SHT_PROGBITS = 1 +- SHT_SYMTAB = 2 +- SHT_STRTAB = 3 +- SHT_RELA = 4 +- SHT_HASH = 5 +- SHT_DYNAMIC = 6 +- SHT_NOTE = 7 +- SHT_NOBITS = 8 +- SHT_REL = 9 +- SHT_SHLIB = 10 +- SHT_DYNSYM = 11 +- SHT_INIT_ARRAY = 14 +- SHT_FINI_ARRAY = 15 +- SHT_PREINIT_ARRAY = 16 +- SHT_GROUP = 17 +- SHT_SYMTAB_SHNDX = 18 +- SHT_RELR = 19 +- SHT_GNU_ATTRIBUTES = 0x6ffffff5 +- SHT_GNU_HASH = 0x6ffffff6 +- SHT_GNU_LIBLIST = 0x6ffffff7 +- SHT_CHECKSUM = 0x6ffffff8 +- SHT_SUNW_move = 0x6ffffffa +- SHT_SUNW_COMDAT = 0x6ffffffb +- SHT_SUNW_syminfo = 0x6ffffffc +- SHT_GNU_verdef = 0x6ffffffd +- SHT_GNU_verneed = 0x6ffffffe +- SHT_GNU_versym = 0x6fffffff +- +-class ShtALPHA(enum.Enum): ++ prefix = 'SHT_' ++class ShtALPHA(Sht): + """Supplemental SHT_* constants for EM_ALPHA.""" +- SHT_ALPHA_DEBUG = 0x70000001 +- SHT_ALPHA_REGINFO = 0x70000002 +- +-class ShtARM(enum.Enum): ++class ShtARM(Sht): + """Supplemental SHT_* constants for EM_ARM.""" +- SHT_ARM_EXIDX = 0x70000001 +- SHT_ARM_PREEMPTMAP = 0x70000002 +- SHT_ARM_ATTRIBUTES = 0x70000003 +- +-class ShtCSKY(enum.Enum): ++class ShtCSKY(Sht): + """Supplemental SHT_* constants for EM_CSKY.""" +- SHT_CSKY_ATTRIBUTES = 0x70000001 +- +-class ShtIA_64(enum.Enum): ++class ShtIA_64(Sht): + """Supplemental SHT_* constants for EM_IA_64.""" +- SHT_IA_64_EXT = 0x70000000 +- SHT_IA_64_UNWIND = 0x70000001 +- +-class ShtMIPS(enum.Enum): ++class ShtMIPS(Sht): + """Supplemental SHT_* constants for EM_MIPS.""" +- SHT_MIPS_LIBLIST = 0x70000000 +- SHT_MIPS_MSYM = 0x70000001 +- SHT_MIPS_CONFLICT = 0x70000002 +- SHT_MIPS_GPTAB = 0x70000003 +- SHT_MIPS_UCODE = 0x70000004 +- SHT_MIPS_DEBUG = 0x70000005 +- SHT_MIPS_REGINFO = 0x70000006 +- SHT_MIPS_PACKAGE = 0x70000007 +- SHT_MIPS_PACKSYM = 0x70000008 +- SHT_MIPS_RELD = 0x70000009 +- SHT_MIPS_IFACE = 0x7000000b +- SHT_MIPS_CONTENT = 0x7000000c +- SHT_MIPS_OPTIONS = 0x7000000d +- SHT_MIPS_SHDR = 0x70000010 +- SHT_MIPS_FDESC = 0x70000011 +- SHT_MIPS_EXTSYM = 0x70000012 +- SHT_MIPS_DENSE = 0x70000013 +- SHT_MIPS_PDESC = 0x70000014 +- SHT_MIPS_LOCSYM = 0x70000015 +- SHT_MIPS_AUXSYM = 0x70000016 +- SHT_MIPS_OPTSYM = 0x70000017 +- SHT_MIPS_LOCSTR = 0x70000018 +- SHT_MIPS_LINE = 0x70000019 +- SHT_MIPS_RFDESC = 0x7000001a +- SHT_MIPS_DELTASYM = 0x7000001b +- SHT_MIPS_DELTAINST = 0x7000001c +- SHT_MIPS_DELTACLASS = 0x7000001d +- SHT_MIPS_DWARF = 0x7000001e +- SHT_MIPS_DELTADECL = 0x7000001f +- SHT_MIPS_SYMBOL_LIB = 0x70000020 +- SHT_MIPS_EVENTS = 0x70000021 +- SHT_MIPS_TRANSLATE = 0x70000022 +- SHT_MIPS_PIXIE = 0x70000023 +- SHT_MIPS_XLATE = 0x70000024 +- SHT_MIPS_XLATE_DEBUG = 0x70000025 +- SHT_MIPS_WHIRL = 0x70000026 +- SHT_MIPS_EH_REGION = 0x70000027 +- SHT_MIPS_XLATE_OLD = 0x70000028 +- SHT_MIPS_PDR_EXCEPTION = 0x70000029 +- SHT_MIPS_XHASH = 0x7000002b +- +-class ShtPARISC(enum.Enum): ++class ShtPARISC(Sht): + """Supplemental SHT_* constants for EM_PARISC.""" +- SHT_PARISC_EXT = 0x70000000 +- SHT_PARISC_UNWIND = 0x70000001 +- SHT_PARISC_DOC = 0x70000002 +- +-class ShtRISCV(enum.Enum): ++class ShtRISCV(Sht): + """Supplemental SHT_* constants for EM_RISCV.""" +- SHT_RISCV_ATTRIBUTES = 0x70000003 +- +-class Pf(enum.IntFlag): ++_register_elf_h(ShtALPHA, prefix='SHT_ALPHA_', parent=Sht) ++_register_elf_h(ShtARM, prefix='SHT_ARM_', parent=Sht) ++_register_elf_h(ShtCSKY, prefix='SHT_CSKY_', parent=Sht) ++_register_elf_h(ShtIA_64, prefix='SHT_IA_64_', parent=Sht) ++_register_elf_h(ShtMIPS, prefix='SHT_MIPS_', parent=Sht) ++_register_elf_h(ShtPARISC, prefix='SHT_PARISC_', parent=Sht) ++_register_elf_h(ShtRISCV, prefix='SHT_RISCV_', parent=Sht) ++_register_elf_h(Sht, ranges=True, ++ skip='SHT_LOSUNW SHT_HISUNW SHT_LOUSER SHT_HIUSER'.split()) ++ ++class Pf(_FlagConstant): + """Program header flags. Type of Phdr.p_flags values.""" +- PF_X = 1 +- PF_W = 2 +- PF_R = 4 +- +-class PfARM(enum.IntFlag): ++ prefix = 'PF_' ++class PfARM(Pf): + """Supplemental PF_* flags for EM_ARM.""" +- PF_ARM_SB = 0x10000000 +- PF_ARM_PI = 0x20000000 +- PF_ARM_ABS = 0x40000000 +- +-class PfPARISC(enum.IntFlag): +- """Supplemental PF_* flags for EM_PARISC.""" +- PF_HP_PAGE_SIZE = 0x00100000 +- PF_HP_FAR_SHARED = 0x00200000 +- PF_HP_NEAR_SHARED = 0x00400000 +- PF_HP_CODE = 0x01000000 +- PF_HP_MODIFY = 0x02000000 +- PF_HP_LAZYSWAP = 0x04000000 +- PF_HP_SBP = 0x08000000 +- +-class PfIA_64(enum.IntFlag): ++class PfHP(Pf): ++ """Supplemental PF_* flags for HP-UX.""" ++class PfIA_64(Pf): + """Supplemental PF_* flags for EM_IA_64.""" +- PF_IA_64_NORECOV = 0x80000000 +- +-class PfMIPS(enum.IntFlag): ++class PfMIPS(Pf): + """Supplemental PF_* flags for EM_MIPS.""" +- PF_MIPS_LOCAL = 0x10000000 +- +-class Shf(enum.IntFlag): ++class PfPARISC(Pf): ++ """Supplemental PF_* flags for EM_PARISC.""" ++_register_elf_h(PfARM, prefix='PF_ARM_', parent=Pf) ++_register_elf_h(PfHP, prefix='PF_HP_', parent=Pf) ++_register_elf_h(PfIA_64, prefix='PF_IA_64_', parent=Pf) ++_register_elf_h(PfMIPS, prefix='PF_MIPS_', parent=Pf) ++_register_elf_h(PfPARISC, prefix='PF_PARISC_', parent=Pf) ++_register_elf_h(Pf, skip='PF_MASKOS PF_MASKPROC'.split()) ++ ++class Shf(_FlagConstant): + """Section flags. Type of Shdr.sh_type values.""" +- SHF_WRITE = 1 << 0 +- SHF_ALLOC = 1 << 1 +- SHF_EXECINSTR = 1 << 2 +- SHF_MERGE = 1 << 4 +- SHF_STRINGS = 1 << 5 +- SHF_INFO_LINK = 1 << 6 +- SHF_LINK_ORDER = 1 << 7 +- SHF_OS_NONCONFORMING = 256 +- SHF_GROUP = 1 << 9 +- SHF_TLS = 1 << 10 +- SHF_COMPRESSED = 1 << 11 +- SHF_GNU_RETAIN = 1 << 21 +- SHF_ORDERED = 1 << 30 +- SHF_EXCLUDE = 1 << 31 +- +-class ShfALPHA(enum.IntFlag): ++ prefix = 'SHF_' ++class ShfALPHA(Shf): + """Supplemental SHF_* constants for EM_ALPHA.""" +- SHF_ALPHA_GPREL = 0x10000000 +- +-class ShfARM(enum.IntFlag): ++class ShfARM(Shf): + """Supplemental SHF_* constants for EM_ARM.""" +- SHF_ARM_ENTRYSECT = 0x10000000 +- SHF_ARM_COMDEF = 0x80000000 +- +-class ShfIA_64(enum.IntFlag): ++class ShfIA_64(Shf): + """Supplemental SHF_* constants for EM_IA_64.""" +- SHF_IA_64_SHORT = 0x10000000 +- SHF_IA_64_NORECOV = 0x20000000 +- +-class ShfMIPS(enum.IntFlag): ++class ShfMIPS(Shf): + """Supplemental SHF_* constants for EM_MIPS.""" +- SHF_MIPS_GPREL = 0x10000000 +- SHF_MIPS_MERGE = 0x20000000 +- SHF_MIPS_ADDR = 0x40000000 +- SHF_MIPS_STRINGS = 0x80000000 +- SHF_MIPS_NOSTRIP = 0x08000000 +- SHF_MIPS_LOCAL = 0x04000000 +- SHF_MIPS_NAMES = 0x02000000 +- SHF_MIPS_NODUPE = 0x01000000 +- +-class ShfPARISC(enum.IntFlag): ++class ShfPARISC(Shf): + """Supplemental SHF_* constants for EM_PARISC.""" +- SHF_PARISC_SHORT = 0x20000000 +- SHF_PARISC_HUGE = 0x40000000 +- SHF_PARISC_SBP = 0x80000000 +- +-class Stb(_OpenIntEnum): ++_register_elf_h(ShfALPHA, prefix='SHF_ALPHA_', parent=Shf) ++_register_elf_h(ShfARM, prefix='SHF_ARM_', parent=Shf) ++_register_elf_h(ShfIA_64, prefix='SHF_IA_64_', parent=Shf) ++_register_elf_h(ShfMIPS, prefix='SHF_MIPS_', parent=Shf) ++_register_elf_h(ShfPARISC, prefix='SHF_PARISC_', parent=Shf) ++_register_elf_h(Shf, skip='SHF_MASKOS SHF_MASKPROC'.split()) ++ ++class Stb(_TypedConstant): + """ELF symbol binding type.""" +- STB_LOCAL = 0 +- STB_GLOBAL = 1 +- STB_WEAK = 2 +- STB_GNU_UNIQUE = 10 +- STB_MIPS_SPLIT_COMMON = 13 ++ prefix = 'STB_' ++_register_elf_h(Stb, ranges=True) + +-class Stt(_OpenIntEnum): ++class Stt(_TypedConstant): + """ELF symbol type.""" +- STT_NOTYPE = 0 +- STT_OBJECT = 1 +- STT_FUNC = 2 +- STT_SECTION = 3 +- STT_FILE = 4 +- STT_COMMON = 5 +- STT_TLS = 6 +- STT_GNU_IFUNC = 10 +- +-class SttARM(enum.Enum): ++ prefix = 'STT_' ++class SttARM(Sht): + """Supplemental STT_* constants for EM_ARM.""" +- STT_ARM_TFUNC = 13 +- STT_ARM_16BIT = 15 +- +-class SttPARISC(enum.Enum): ++class SttPARISC(Sht): + """Supplemental STT_* constants for EM_PARISC.""" +- STT_HP_OPAQUE = 11 +- STT_HP_STUB = 12 +- STT_PARISC_MILLICODE = 13 +- +-class SttSPARC(enum.Enum): ++class SttSPARC(Sht): + """Supplemental STT_* constants for EM_SPARC.""" + STT_SPARC_REGISTER = 13 +- +-class SttX86_64(enum.Enum): ++class SttX86_64(Sht): + """Supplemental STT_* constants for EM_X86_64.""" +- SHT_X86_64_UNWIND = 0x70000001 ++_register_elf_h(SttARM, prefix='STT_ARM_', parent=Stt) ++_register_elf_h(SttPARISC, prefix='STT_PARISC_', parent=Stt) ++_register_elf_h(SttSPARC, prefix='STT_SPARC_', parent=Stt) ++_register_elf_h(Stt, ranges=True) ++ + +-class Pt(_OpenIntEnum): ++class Pt(_TypedConstant): + """ELF program header types. Type of Phdr.p_type.""" +- PT_NULL = 0 +- PT_LOAD = 1 +- PT_DYNAMIC = 2 +- PT_INTERP = 3 +- PT_NOTE = 4 +- PT_SHLIB = 5 +- PT_PHDR = 6 +- PT_TLS = 7 +- PT_NUM = 8 +- PT_GNU_EH_FRAME = 0x6474e550 +- PT_GNU_STACK = 0x6474e551 +- PT_GNU_RELRO = 0x6474e552 +- PT_GNU_PROPERTY = 0x6474e553 +- PT_SUNWBSS = 0x6ffffffa +- PT_SUNWSTACK = 0x6ffffffb +- +-class PtAARCH64(enum.Enum): ++ prefix = 'PT_' ++class PtAARCH64(Pt): + """Supplemental PT_* constants for EM_AARCH64.""" +- PT_AARCH64_MEMTAG_MTE = 0x70000002 +- +-class PtARM(enum.Enum): ++class PtARM(Pt): + """Supplemental PT_* constants for EM_ARM.""" +- PT_ARM_EXIDX = 0x70000001 +- +-class PtIA_64(enum.Enum): ++class PtHP(Pt): ++ """Supplemental PT_* constants for HP-U.""" ++class PtIA_64(Pt): + """Supplemental PT_* constants for EM_IA_64.""" +- PT_IA_64_HP_OPT_ANOT = 0x60000012 +- PT_IA_64_HP_HSL_ANOT = 0x60000013 +- PT_IA_64_HP_STACK = 0x60000014 +- PT_IA_64_ARCHEXT = 0x70000000 +- PT_IA_64_UNWIND = 0x70000001 +- +-class PtMIPS(enum.Enum): ++class PtMIPS(Pt): + """Supplemental PT_* constants for EM_MIPS.""" +- PT_MIPS_REGINFO = 0x70000000 +- PT_MIPS_RTPROC = 0x70000001 +- PT_MIPS_OPTIONS = 0x70000002 +- PT_MIPS_ABIFLAGS = 0x70000003 +- +-class PtPARISC(enum.Enum): ++class PtPARISC(Pt): + """Supplemental PT_* constants for EM_PARISC.""" +- PT_HP_TLS = 0x60000000 +- PT_HP_CORE_NONE = 0x60000001 +- PT_HP_CORE_VERSION = 0x60000002 +- PT_HP_CORE_KERNEL = 0x60000003 +- PT_HP_CORE_COMM = 0x60000004 +- PT_HP_CORE_PROC = 0x60000005 +- PT_HP_CORE_LOADABLE = 0x60000006 +- PT_HP_CORE_STACK = 0x60000007 +- PT_HP_CORE_SHM = 0x60000008 +- PT_HP_CORE_MMF = 0x60000009 +- PT_HP_PARALLEL = 0x60000010 +- PT_HP_FASTBIND = 0x60000011 +- PT_HP_OPT_ANNOT = 0x60000012 +- PT_HP_HSL_ANNOT = 0x60000013 +- PT_HP_STACK = 0x60000014 +- PT_PARISC_ARCHEXT = 0x70000000 +- PT_PARISC_UNWIND = 0x70000001 +- +-class PtRISCV(enum.Enum): ++class PtRISCV(Pt): + """Supplemental PT_* constants for EM_RISCV.""" +- PT_RISCV_ATTRIBUTES = 0x70000003 +- +-class Dt(_OpenIntEnum): ++_register_elf_h(PtAARCH64, prefix='PT_AARCH64_', parent=Pt) ++_register_elf_h(PtARM, prefix='PT_ARM_', parent=Pt) ++_register_elf_h(PtHP, prefix='PT_HP_', parent=Pt) ++_register_elf_h(PtIA_64, prefix='PT_IA_64_', parent=Pt) ++_register_elf_h(PtMIPS, prefix='PT_MIPS_', parent=Pt) ++_register_elf_h(PtPARISC, prefix='PT_PARISC_', parent=Pt) ++_register_elf_h(PtRISCV, prefix='PT_RISCV_', parent=Pt) ++_register_elf_h(Pt, skip='PT_LOSUNW PT_HISUNW'.split(), ranges=True) ++ ++class Dt(_TypedConstant): + """ELF dynamic segment tags. Type of Dyn.d_val.""" +- DT_NULL = 0 +- DT_NEEDED = 1 +- DT_PLTRELSZ = 2 +- DT_PLTGOT = 3 +- DT_HASH = 4 +- DT_STRTAB = 5 +- DT_SYMTAB = 6 +- DT_RELA = 7 +- DT_RELASZ = 8 +- DT_RELAENT = 9 +- DT_STRSZ = 10 +- DT_SYMENT = 11 +- DT_INIT = 12 +- DT_FINI = 13 +- DT_SONAME = 14 +- DT_RPATH = 15 +- DT_SYMBOLIC = 16 +- DT_REL = 17 +- DT_RELSZ = 18 +- DT_RELENT = 19 +- DT_PLTREL = 20 +- DT_DEBUG = 21 +- DT_TEXTREL = 22 +- DT_JMPREL = 23 +- DT_BIND_NOW = 24 +- DT_INIT_ARRAY = 25 +- DT_FINI_ARRAY = 26 +- DT_INIT_ARRAYSZ = 27 +- DT_FINI_ARRAYSZ = 28 +- DT_RUNPATH = 29 +- DT_FLAGS = 30 +- DT_PREINIT_ARRAY = 32 +- DT_PREINIT_ARRAYSZ = 33 +- DT_SYMTAB_SHNDX = 34 +- DT_RELRSZ = 35 +- DT_RELR = 36 +- DT_RELRENT = 37 +- DT_GNU_PRELINKED = 0x6ffffdf5 +- DT_GNU_CONFLICTSZ = 0x6ffffdf6 +- DT_GNU_LIBLISTSZ = 0x6ffffdf7 +- DT_CHECKSUM = 0x6ffffdf8 +- DT_PLTPADSZ = 0x6ffffdf9 +- DT_MOVEENT = 0x6ffffdfa +- DT_MOVESZ = 0x6ffffdfb +- DT_FEATURE_1 = 0x6ffffdfc +- DT_POSFLAG_1 = 0x6ffffdfd +- DT_SYMINSZ = 0x6ffffdfe +- DT_SYMINENT = 0x6ffffdff +- DT_GNU_HASH = 0x6ffffef5 +- DT_TLSDESC_PLT = 0x6ffffef6 +- DT_TLSDESC_GOT = 0x6ffffef7 +- DT_GNU_CONFLICT = 0x6ffffef8 +- DT_GNU_LIBLIST = 0x6ffffef9 +- DT_CONFIG = 0x6ffffefa +- DT_DEPAUDIT = 0x6ffffefb +- DT_AUDIT = 0x6ffffefc +- DT_PLTPAD = 0x6ffffefd +- DT_MOVETAB = 0x6ffffefe +- DT_SYMINFO = 0x6ffffeff +- DT_VERSYM = 0x6ffffff0 +- DT_RELACOUNT = 0x6ffffff9 +- DT_RELCOUNT = 0x6ffffffa +- DT_FLAGS_1 = 0x6ffffffb +- DT_VERDEF = 0x6ffffffc +- DT_VERDEFNUM = 0x6ffffffd +- DT_VERNEED = 0x6ffffffe +- DT_VERNEEDNUM = 0x6fffffff +- DT_AUXILIARY = 0x7ffffffd +- DT_FILTER = 0x7fffffff +- +-class DtAARCH64(enum.Enum): ++ prefix = 'DT_' ++class DtAARCH64(Dt): + """Supplemental DT_* constants for EM_AARCH64.""" +- DT_AARCH64_BTI_PLT = 0x70000001 +- DT_AARCH64_PAC_PLT = 0x70000003 +- DT_AARCH64_VARIANT_PCS = 0x70000005 +- +-class DtALPHA(enum.Enum): ++class DtALPHA(Dt): + """Supplemental DT_* constants for EM_ALPHA.""" +- DT_ALPHA_PLTRO = 0x70000000 +- +-class DtALTERA_NIOS2(enum.Enum): ++class DtALTERA_NIOS2(Dt): + """Supplemental DT_* constants for EM_ALTERA_NIOS2.""" +- DT_NIOS2_GP = 0x70000002 +- +-class DtIA_64(enum.Enum): ++class DtIA_64(Dt): + """Supplemental DT_* constants for EM_IA_64.""" +- DT_IA_64_PLT_RESERVE = 0x70000000 +- +-class DtMIPS(enum.Enum): ++class DtMIPS(Dt): + """Supplemental DT_* constants for EM_MIPS.""" +- DT_MIPS_RLD_VERSION = 0x70000001 +- DT_MIPS_TIME_STAMP = 0x70000002 +- DT_MIPS_ICHECKSUM = 0x70000003 +- DT_MIPS_IVERSION = 0x70000004 +- DT_MIPS_FLAGS = 0x70000005 +- DT_MIPS_BASE_ADDRESS = 0x70000006 +- DT_MIPS_MSYM = 0x70000007 +- DT_MIPS_CONFLICT = 0x70000008 +- DT_MIPS_LIBLIST = 0x70000009 +- DT_MIPS_LOCAL_GOTNO = 0x7000000a +- DT_MIPS_CONFLICTNO = 0x7000000b +- DT_MIPS_LIBLISTNO = 0x70000010 +- DT_MIPS_SYMTABNO = 0x70000011 +- DT_MIPS_UNREFEXTNO = 0x70000012 +- DT_MIPS_GOTSYM = 0x70000013 +- DT_MIPS_HIPAGENO = 0x70000014 +- DT_MIPS_RLD_MAP = 0x70000016 +- DT_MIPS_DELTA_CLASS = 0x70000017 +- DT_MIPS_DELTA_CLASS_NO = 0x70000018 +- DT_MIPS_DELTA_INSTANCE = 0x70000019 +- DT_MIPS_DELTA_INSTANCE_NO = 0x7000001a +- DT_MIPS_DELTA_RELOC = 0x7000001b +- DT_MIPS_DELTA_RELOC_NO = 0x7000001c +- DT_MIPS_DELTA_SYM = 0x7000001d +- DT_MIPS_DELTA_SYM_NO = 0x7000001e +- DT_MIPS_DELTA_CLASSSYM = 0x70000020 +- DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021 +- DT_MIPS_CXX_FLAGS = 0x70000022 +- DT_MIPS_PIXIE_INIT = 0x70000023 +- DT_MIPS_SYMBOL_LIB = 0x70000024 +- DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025 +- DT_MIPS_LOCAL_GOTIDX = 0x70000026 +- DT_MIPS_HIDDEN_GOTIDX = 0x70000027 +- DT_MIPS_PROTECTED_GOTIDX = 0x70000028 +- DT_MIPS_OPTIONS = 0x70000029 +- DT_MIPS_INTERFACE = 0x7000002a +- DT_MIPS_DYNSTR_ALIGN = 0x7000002b +- DT_MIPS_INTERFACE_SIZE = 0x7000002c +- DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002d +- DT_MIPS_PERF_SUFFIX = 0x7000002e +- DT_MIPS_COMPACT_SIZE = 0x7000002f +- DT_MIPS_GP_VALUE = 0x70000030 +- DT_MIPS_AUX_DYNAMIC = 0x70000031 +- DT_MIPS_PLTGOT = 0x70000032 +- DT_MIPS_RWPLT = 0x70000034 +- DT_MIPS_RLD_MAP_REL = 0x70000035 +- DT_MIPS_XHASH = 0x70000036 +- +-class DtPPC(enum.Enum): ++class DtPPC(Dt): + """Supplemental DT_* constants for EM_PPC.""" +- DT_PPC_GOT = 0x70000000 +- DT_PPC_OPT = 0x70000001 +- +-class DtPPC64(enum.Enum): ++class DtPPC64(Dt): + """Supplemental DT_* constants for EM_PPC64.""" +- DT_PPC64_GLINK = 0x70000000 +- DT_PPC64_OPD = 0x70000001 +- DT_PPC64_OPDSZ = 0x70000002 +- DT_PPC64_OPT = 0x70000003 +- +-class DtRISCV(enum.Enum): ++class DtRISCV(Dt): + """Supplemental DT_* constants for EM_RISCV.""" +- DT_RISCV_VARIANT_CC = 0x70000001 +- +-class DtSPARC(enum.Enum): ++class DtSPARC(Dt): + """Supplemental DT_* constants for EM_SPARC.""" +- DT_SPARC_REGISTER = 0x70000001 ++_dt_skip = ''' ++DT_ENCODING DT_PROCNUM ++DT_ADDRRNGLO DT_ADDRRNGHI DT_ADDRNUM ++DT_VALRNGLO DT_VALRNGHI DT_VALNUM ++DT_VERSIONTAGNUM DT_EXTRANUM ++DT_AARCH64_NUM ++DT_ALPHA_NUM ++DT_IA_64_NUM ++DT_MIPS_NUM ++DT_PPC_NUM ++DT_PPC64_NUM ++DT_SPARC_NUM ++'''.strip().split() ++_register_elf_h(DtAARCH64, prefix='DT_AARCH64_', skip=_dt_skip, parent=Dt) ++_register_elf_h(DtALPHA, prefix='DT_ALPHA_', skip=_dt_skip, parent=Dt) ++_register_elf_h(DtALTERA_NIOS2, prefix='DT_NIOS2_', skip=_dt_skip, parent=Dt) ++_register_elf_h(DtIA_64, prefix='DT_IA_64_', skip=_dt_skip, parent=Dt) ++_register_elf_h(DtMIPS, prefix='DT_MIPS_', skip=_dt_skip, parent=Dt) ++_register_elf_h(DtPPC, prefix='DT_PPC_', skip=_dt_skip, parent=Dt) ++_register_elf_h(DtPPC64, prefix='DT_PPC64_', skip=_dt_skip, parent=Dt) ++_register_elf_h(DtRISCV, prefix='DT_RISCV_', skip=_dt_skip, parent=Dt) ++_register_elf_h(DtSPARC, prefix='DT_SPARC_', skip=_dt_skip, parent=Dt) ++_register_elf_h(Dt, skip=_dt_skip, ranges=True) ++del _dt_skip ++ ++# Constant extraction is complete. ++del _register_elf_h ++del _elf_h + + class StInfo: + """ELF symbol binding and type. Type of the Sym.st_info field.""" diff --git a/glibc-rh2109510-22.patch b/glibc-rh2109510-22.patch new file mode 100644 index 0000000..e87b99f --- /dev/null +++ b/glibc-rh2109510-22.patch @@ -0,0 +1,34 @@ +commit d33705c0b020632274318323931695a99753b5be +Author: Florian Weimer +Date: Thu Nov 3 12:24:17 2022 +0100 + + scripts/glibcelf.py: Properly report parsing failures + + Without this change, parse failures result in an exception: + + Traceback (most recent call last): + File "tst-glibcelf.py", line 23, in + import glibcelf + File "/path/to/git/scripts/glibcelf.py", line 226, in + _elf_h = _parse_elf_h() + File "/path/to/git/scripts/glibcelf.py", line 221, in _parse_elf_h + result = glibcpp.macro_eval(glibcpp.macro_definitions(tokens), reporter) + File "/path/to/git/scripts/glibcpp.py", line 379, in macro_eval + reporter.error(md.line, 'macro {} redefined'.format(md.name)) + File "/path/to/git/scripts/glibcelf.py", line 214, in error + errors += 1 + UnboundLocalError: local variable 'errors' referenced before assignment + +diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py +index 420cb21943b28bba..59aab56ecf9deb3e 100644 +--- a/scripts/glibcelf.py ++++ b/scripts/glibcelf.py +@@ -211,7 +211,7 @@ def _parse_elf_h(): + self.errors = 0 + + def error(self, line, message): +- errors += 1 ++ self.errors += 1 + print('{}:{}: error: {}'.format(path, line, message)) + + def note(self, line, message): diff --git a/glibc-rh2109510-23.patch b/glibc-rh2109510-23.patch new file mode 100644 index 0000000..7823014 --- /dev/null +++ b/glibc-rh2109510-23.patch @@ -0,0 +1,108 @@ +Downstream-only adjustments to scripts/glibcelf.py. We do not have +CSKY nor RISC-V constants in , so glibcelf cannot extract +those. PT_AARCH64_* constants are missing as well. + +Adjust elf/tst-glibcelf.py to use PT_MIPS_OPTIONS instead of +PT_AARCH64_MEMTAG_MTE for testing. It has the same numeric value +(0x70000002). + +diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py +index a5bff45eae55edea..9cb0861589d6ae2e 100644 +--- a/elf/tst-glibcelf.py ++++ b/elf/tst-glibcelf.py +@@ -75,15 +75,17 @@ def check_basic(): + if repr(glibcelf.Pt(17609)) != 'Pt(17609)': + error('repr(Pt(17609))') + +- if glibcelf.Pt('PT_AARCH64_MEMTAG_MTE') \ +- is not glibcelf.Pt.PT_AARCH64_MEMTAG_MTE: +- error('PT_AARCH64_MEMTAG_MTE identity') +- if glibcelf.Pt(0x70000002) is glibcelf.Pt.PT_AARCH64_MEMTAG_MTE: ++ # Note: Upstream uses PT_AARCH64_MEMTAG_MTE instead of PT_MIPS_OPTIONS. ++ # PT_AARCH64_MEMTAG_MTE is not yet available downstream. ++ if glibcelf.Pt('PT_MIPS_OPTIONS') \ ++ is not glibcelf.Pt.PT_MIPS_OPTIONS: ++ error('PT_MIPS_OPTIONS identity') ++ if glibcelf.Pt(0x70000002) is glibcelf.Pt.PT_MIPS_OPTIONS: + error('Pt(0x70000002) identity') +- if glibcelf.PtAARCH64(0x70000002) is not glibcelf.Pt.PT_AARCH64_MEMTAG_MTE: +- error('PtAARCH64(0x70000002) identity') +- if glibcelf.Pt.PT_AARCH64_MEMTAG_MTE.short_name != 'AARCH64_MEMTAG_MTE': +- error('PT_AARCH64_MEMTAG_MTE short name') ++ if glibcelf.PtMIPS(0x70000002) is not glibcelf.Pt.PT_MIPS_OPTIONS: ++ error('PtMIPS(0x70000002) identity') ++ if glibcelf.Pt.PT_MIPS_OPTIONS.short_name != 'MIPS_OPTIONS': ++ error('PT_MIPS_OPTIONS short name') + + # Special cases for int-like Shn. + if glibcelf.Shn(32) == glibcelf.Shn.SHN_XINDEX: +diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py +index 59aab56ecf9deb3e..5980d7cc906005e2 100644 +--- a/scripts/glibcelf.py ++++ b/scripts/glibcelf.py +@@ -306,23 +306,17 @@ class ShtALPHA(Sht): + """Supplemental SHT_* constants for EM_ALPHA.""" + class ShtARM(Sht): + """Supplemental SHT_* constants for EM_ARM.""" +-class ShtCSKY(Sht): +- """Supplemental SHT_* constants for EM_CSKY.""" + class ShtIA_64(Sht): + """Supplemental SHT_* constants for EM_IA_64.""" + class ShtMIPS(Sht): + """Supplemental SHT_* constants for EM_MIPS.""" + class ShtPARISC(Sht): + """Supplemental SHT_* constants for EM_PARISC.""" +-class ShtRISCV(Sht): +- """Supplemental SHT_* constants for EM_RISCV.""" + _register_elf_h(ShtALPHA, prefix='SHT_ALPHA_', parent=Sht) + _register_elf_h(ShtARM, prefix='SHT_ARM_', parent=Sht) +-_register_elf_h(ShtCSKY, prefix='SHT_CSKY_', parent=Sht) + _register_elf_h(ShtIA_64, prefix='SHT_IA_64_', parent=Sht) + _register_elf_h(ShtMIPS, prefix='SHT_MIPS_', parent=Sht) + _register_elf_h(ShtPARISC, prefix='SHT_PARISC_', parent=Sht) +-_register_elf_h(ShtRISCV, prefix='SHT_RISCV_', parent=Sht) + _register_elf_h(Sht, ranges=True, + skip='SHT_LOSUNW SHT_HISUNW SHT_LOUSER SHT_HIUSER'.split()) + +@@ -392,8 +386,6 @@ _register_elf_h(Stt, ranges=True) + class Pt(_TypedConstant): + """ELF program header types. Type of Phdr.p_type.""" + prefix = 'PT_' +-class PtAARCH64(Pt): +- """Supplemental PT_* constants for EM_AARCH64.""" + class PtARM(Pt): + """Supplemental PT_* constants for EM_ARM.""" + class PtHP(Pt): +@@ -404,15 +396,11 @@ class PtMIPS(Pt): + """Supplemental PT_* constants for EM_MIPS.""" + class PtPARISC(Pt): + """Supplemental PT_* constants for EM_PARISC.""" +-class PtRISCV(Pt): +- """Supplemental PT_* constants for EM_RISCV.""" +-_register_elf_h(PtAARCH64, prefix='PT_AARCH64_', parent=Pt) + _register_elf_h(PtARM, prefix='PT_ARM_', parent=Pt) + _register_elf_h(PtHP, prefix='PT_HP_', parent=Pt) + _register_elf_h(PtIA_64, prefix='PT_IA_64_', parent=Pt) + _register_elf_h(PtMIPS, prefix='PT_MIPS_', parent=Pt) + _register_elf_h(PtPARISC, prefix='PT_PARISC_', parent=Pt) +-_register_elf_h(PtRISCV, prefix='PT_RISCV_', parent=Pt) + _register_elf_h(Pt, skip='PT_LOSUNW PT_HISUNW'.split(), ranges=True) + + class Dt(_TypedConstant): +@@ -432,8 +420,6 @@ class DtPPC(Dt): + """Supplemental DT_* constants for EM_PPC.""" + class DtPPC64(Dt): + """Supplemental DT_* constants for EM_PPC64.""" +-class DtRISCV(Dt): +- """Supplemental DT_* constants for EM_RISCV.""" + class DtSPARC(Dt): + """Supplemental DT_* constants for EM_SPARC.""" + _dt_skip = ''' +@@ -456,7 +442,6 @@ _register_elf_h(DtIA_64, prefix='DT_IA_64_', skip=_dt_skip, parent=Dt) + _register_elf_h(DtMIPS, prefix='DT_MIPS_', skip=_dt_skip, parent=Dt) + _register_elf_h(DtPPC, prefix='DT_PPC_', skip=_dt_skip, parent=Dt) + _register_elf_h(DtPPC64, prefix='DT_PPC64_', skip=_dt_skip, parent=Dt) +-_register_elf_h(DtRISCV, prefix='DT_RISCV_', skip=_dt_skip, parent=Dt) + _register_elf_h(DtSPARC, prefix='DT_SPARC_', skip=_dt_skip, parent=Dt) + _register_elf_h(Dt, skip=_dt_skip, ranges=True) + del _dt_skip diff --git a/glibc-rh2109510-3.patch b/glibc-rh2109510-3.patch new file mode 100644 index 0000000..59496a7 --- /dev/null +++ b/glibc-rh2109510-3.patch @@ -0,0 +1,32 @@ +commit 7b36d26b22d147ffc347f427f9fd584700578a94 +Author: Samuel Thibault +Date: Mon Dec 3 14:40:48 2018 +0100 + + Fix test-as-const-jmp_buf-ssp.c generation on gnu-i386 + + hurd's jmp_buf-ssp.sym does not define any symbol. + scripts/gen-as-const.py currently was emitting an empty line in that + case, and the gawk invocation was prepending "asconst_" to it, ending up + with: + + .../build/glibc/setjmp/test-as-const-jmp_buf-ssp.c:1:2: error: expected « = », « , », « ; », « asm » or + « __attribute__ » at end of input + 1 | asconst_ + | ^~~~~~~~ + + * scripts/gen-as-const.py (main): Avoid emitting empty line when + there is no element in `consts'. + +diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py +index b7a5744bb192dd67..cabf401ed15e8367 100644 +--- a/scripts/gen-as-const.py ++++ b/scripts/gen-as-const.py +@@ -153,7 +153,7 @@ def main(): + print(gen_test(sym_data)) + else: + consts = compute_c_consts(sym_data, args.cc) +- print('\n'.join('#define %s %s' % c for c in sorted(consts.items()))) ++ print(''.join('#define %s %s\n' % c for c in sorted(consts.items())), end='') + + if __name__ == '__main__': + main() diff --git a/glibc-rh2109510-4.patch b/glibc-rh2109510-4.patch new file mode 100644 index 0000000..a56943a --- /dev/null +++ b/glibc-rh2109510-4.patch @@ -0,0 +1,157 @@ +commit 477a02f63751c4b759ddd9454d17f2a7ad120ee3 +Author: Joseph Myers +Date: Mon Dec 3 22:08:50 2018 +0000 + + Make gen-as-const.py handle '--' consistently with awk script. + + It was reported in + that + gen-as-const.py fails to generate test code in the case where a .sym + file has no symbols in it, so resulting in a test failing to link for + Hurd. + + The relevant difference from the old awk script is that the old script + treated '--' lines as indicating that the text to do at the start of + the test (or file used to compute constants) should be output at that + point if not already output, as well as treating lines with actual + entries for constants like that. This patch changes gen-as-const.py + accordingly, making it the sole responsibility of the code parsing + .sym files to determine when such text should be output and ensuring + it's always output at some point even if there are no symbols and no + '--' lines, since not outputting it means the test fails to link. + Handling '--' like that also avoids any problems that would arise if + the first entry for a symbol were inside #ifdef (since the text in + question must not be output inside #ifdef). + + Tested for x86_64, and with build-many-glibcs.py for i686-gnu. Note + that there are still compilation test failures for i686-gnu + (linknamespace tests, possibly arising from recent posix_spawn-related + changes). + + * scripts/gen-as-const.py (compute_c_consts): Take an argument + 'START' to indicate that start text should be output. + (gen_test): Likewise. + (main): Generate 'START' for first symbol or '--' line, or at end + of input if not previously generated. + +diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py +index cabf401ed15e8367..eb85ef1aa0f4934d 100644 +--- a/scripts/gen-as-const.py ++++ b/scripts/gen-as-const.py +@@ -34,28 +34,28 @@ def compute_c_consts(sym_data, cc): + """Compute the values of some C constants. + + The first argument is a list whose elements are either strings +- (preprocessor directives) or pairs of strings (a name and a C ++ (preprocessor directives, or the special string 'START' to ++ indicate this function should insert its initial boilerplate text ++ in the output there) or pairs of strings (a name and a C + expression for the corresponding value). Preprocessor directives + in the middle of the list may be used to select which constants + end up being evaluated using which expressions. + + """ + out_lines = [] +- started = False + for arg in sym_data: + if isinstance(arg, str): +- out_lines.append(arg) ++ if arg == 'START': ++ out_lines.append('void\ndummy (void)\n{') ++ else: ++ out_lines.append(arg) + continue + name = arg[0] + value = arg[1] +- if not started: +- out_lines.append('void\ndummy (void)\n{') +- started = True + out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" ' + ': : \"i\" ((long int) (%s)));' + % (name, value)) +- if started: +- out_lines.append('}') ++ out_lines.append('}') + out_lines.append('') + out_text = '\n'.join(out_lines) + with tempfile.TemporaryDirectory() as temp_dir: +@@ -89,32 +89,32 @@ def gen_test(sym_data): + + """ + out_lines = [] +- started = False + for arg in sym_data: + if isinstance(arg, str): +- out_lines.append(arg) ++ if arg == 'START': ++ out_lines.append('#include \n' ++ '#include \n' ++ '#include \n' ++ '#if __WORDSIZE == 64\n' ++ 'typedef uint64_t c_t;\n' ++ '# define U(n) UINT64_C (n)\n' ++ '#else\n' ++ 'typedef uint32_t c_t;\n' ++ '# define U(n) UINT32_C (n)\n' ++ '#endif\n' ++ 'static int\n' ++ 'do_test (void)\n' ++ '{\n' ++ # Compilation test only, using static ++ # assertions. ++ ' return 0;\n' ++ '}\n' ++ '#include ') ++ else: ++ out_lines.append(arg) + continue + name = arg[0] + value = arg[1] +- if not started: +- out_lines.append('#include \n' +- '#include \n' +- '#include \n' +- '#if __WORDSIZE == 64\n' +- 'typedef uint64_t c_t;\n' +- '# define U(n) UINT64_C (n)\n' +- '#else\n' +- 'typedef uint32_t c_t;\n' +- '# define U(n) UINT32_C (n)\n' +- '#endif\n' +- 'static int\n' +- 'do_test (void)\n' +- '{\n' +- # Compilation test only, using static assertions. +- ' return 0;\n' +- '}\n' +- '#include ') +- started = True + out_lines.append('_Static_assert (U (asconst_%s) == (c_t) (%s), ' + '"value of %s");' + % (name, value, name)) +@@ -134,6 +134,7 @@ def main(): + args = parser.parse_args() + sym_data = [] + with open(args.sym_file, 'r') as sym_file: ++ started = False + for line in sym_file: + line = line.strip() + if line == '': +@@ -143,12 +144,17 @@ def main(): + sym_data.append(line) + continue + words = line.split(maxsplit=1) ++ if not started: ++ sym_data.append('START') ++ started = True + # Separator. + if words[0] == '--': + continue + name = words[0] + value = words[1] if len(words) > 1 else words[0] + sym_data.append((name, value)) ++ if not started: ++ sym_data.append('START') + if args.test: + print(gen_test(sym_data)) + else: diff --git a/glibc-rh2109510-5.patch b/glibc-rh2109510-5.patch new file mode 100644 index 0000000..3e93b78 --- /dev/null +++ b/glibc-rh2109510-5.patch @@ -0,0 +1,483 @@ +commit a8110b727e508f7ddf34f940af622e6f95435201 +Author: Joseph Myers +Date: Mon Dec 10 22:27:13 2018 +0000 + + Move tst-signal-numbers to Python. + + This patch converts the tst-signal-numbers test from shell + awk to + Python. + + As with gen-as-const, the point is not so much that shell and awk are + problematic for this code, as that it's useful to build up general + infrastructure in Python for use of a range of code involving + extracting values from C headers. This patch moves some code from + gen-as-const.py to a new glibcextract.py, which also gains functions + relating to listing macros, and comparing the values of a set of + macros from compiling two different pieces of code. + + It's not just signal numbers that should have such tests; pretty much + any case where glibc copies constants from Linux kernel headers should + have such tests that the values and sets of constants agree except + where differences are known to be OK. Much the same also applies to + structure layouts (although testing those without hardcoding lists of + fields to test will be more complicated). + + Given this patch, another test for a set of macros would essentially + be just a call to glibcextract.compare_macro_consts (plus boilerplate + code - and we could move to having separate text files defining such + tests, like the .sym inputs to gen-as-const, so that only a single + Python script is needed for most such tests). Some such tests would + of course need new features, e.g. where the set of macros changes in + new kernel versions (so you need to allow new macro names on the + kernel side if the kernel headers are newer than the version known to + glibc, and extra macros on the glibc side if the kernel headers are + older). tst-syscall-list.sh could become a Python script that uses + common code to generate lists of macros but does other things with its + own custom logic. + + There are a few differences from the existing shell + awk test. + Because the new test evaluates constants using the compiler, no + special handling is needed any more for one signal name being defined + to another. Because asm/signal.h now needs to pass through the + compiler, not just the preprocessor, stddef.h is included as well + (given the asm/signal.h issue that it requires an externally provided + definition of size_t). The previous code defined __ASSEMBLER__ with + asm/signal.h; this is removed (__ASSEMBLY__, a different macro, + eliminates the requirement for stddef.h on some but not all + architectures). + + Tested for x86_64, and with build-many-glibcs.py. + + * scripts/glibcextract.py: New file. + * scripts/gen-as-const.py: Do not import os.path, re, subprocess + or tempfile. Import glibcexctract. + (compute_c_consts): Remove. Moved to glibcextract.py. + (gen_test): Update reference to compute_c_consts. + (main): Likewise. + * sysdeps/unix/sysv/linux/tst-signal-numbers.py: New file. + * sysdeps/unix/sysv/linux/tst-signal-numbers.sh: Remove. + * sysdeps/unix/sysv/linux/Makefile + ($(objpfx)tst-signal-numbers.out): Use tst-signal-numbers.py. + Redirect stderr as well as stdout. + +diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py +index eb85ef1aa0f4934d..f85e359394acb1a4 100644 +--- a/scripts/gen-as-const.py ++++ b/scripts/gen-as-const.py +@@ -24,68 +24,14 @@ + # A line giving just a name implies an expression consisting of just that name. + + import argparse +-import os.path +-import re +-import subprocess +-import tempfile + +- +-def compute_c_consts(sym_data, cc): +- """Compute the values of some C constants. +- +- The first argument is a list whose elements are either strings +- (preprocessor directives, or the special string 'START' to +- indicate this function should insert its initial boilerplate text +- in the output there) or pairs of strings (a name and a C +- expression for the corresponding value). Preprocessor directives +- in the middle of the list may be used to select which constants +- end up being evaluated using which expressions. +- +- """ +- out_lines = [] +- for arg in sym_data: +- if isinstance(arg, str): +- if arg == 'START': +- out_lines.append('void\ndummy (void)\n{') +- else: +- out_lines.append(arg) +- continue +- name = arg[0] +- value = arg[1] +- out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" ' +- ': : \"i\" ((long int) (%s)));' +- % (name, value)) +- out_lines.append('}') +- out_lines.append('') +- out_text = '\n'.join(out_lines) +- with tempfile.TemporaryDirectory() as temp_dir: +- c_file_name = os.path.join(temp_dir, 'test.c') +- s_file_name = os.path.join(temp_dir, 'test.s') +- with open(c_file_name, 'w') as c_file: +- c_file.write(out_text) +- # Compilation has to be from stdin to avoid the temporary file +- # name being written into the generated dependencies. +- cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name)) +- subprocess.check_call(cmd, shell=True) +- consts = {} +- with open(s_file_name, 'r') as s_file: +- for line in s_file: +- match = re.search('@@@name@@@([^@]*)' +- '@@@value@@@[^0-9Xxa-fA-F-]*' +- '([0-9Xxa-fA-F-]+).*@@@end@@@', line) +- if match: +- if (match.group(1) in consts +- and match.group(2) != consts[match.group(1)]): +- raise ValueError('duplicate constant %s' +- % match.group(1)) +- consts[match.group(1)] = match.group(2) +- return consts ++import glibcextract + + + def gen_test(sym_data): + """Generate a test for the values of some C constants. + +- The first argument is as for compute_c_consts. ++ The first argument is as for glibcextract.compute_c_consts. + + """ + out_lines = [] +@@ -158,7 +104,7 @@ def main(): + if args.test: + print(gen_test(sym_data)) + else: +- consts = compute_c_consts(sym_data, args.cc) ++ consts = glibcextract.compute_c_consts(sym_data, args.cc) + print(''.join('#define %s %s\n' % c for c in sorted(consts.items())), end='') + + if __name__ == '__main__': +diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py +new file mode 100644 +index 0000000000000000..ecc4d5b6cc387c7d +--- /dev/null ++++ b/scripts/glibcextract.py +@@ -0,0 +1,162 @@ ++#!/usr/bin/python3 ++# Extract information from C headers. ++# Copyright (C) 2018 Free Software Foundation, Inc. ++# This file is part of the GNU C Library. ++# ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++# ++# The GNU C Library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# . ++ ++import os.path ++import re ++import subprocess ++import tempfile ++ ++ ++def compute_c_consts(sym_data, cc): ++ """Compute the values of some C constants. ++ ++ The first argument is a list whose elements are either strings ++ (preprocessor directives, or the special string 'START' to ++ indicate this function should insert its initial boilerplate text ++ in the output there) or pairs of strings (a name and a C ++ expression for the corresponding value). Preprocessor directives ++ in the middle of the list may be used to select which constants ++ end up being evaluated using which expressions. ++ ++ """ ++ out_lines = [] ++ for arg in sym_data: ++ if isinstance(arg, str): ++ if arg == 'START': ++ out_lines.append('void\ndummy (void)\n{') ++ else: ++ out_lines.append(arg) ++ continue ++ name = arg[0] ++ value = arg[1] ++ out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" ' ++ ': : \"i\" ((long int) (%s)));' ++ % (name, value)) ++ out_lines.append('}') ++ out_lines.append('') ++ out_text = '\n'.join(out_lines) ++ with tempfile.TemporaryDirectory() as temp_dir: ++ c_file_name = os.path.join(temp_dir, 'test.c') ++ s_file_name = os.path.join(temp_dir, 'test.s') ++ with open(c_file_name, 'w') as c_file: ++ c_file.write(out_text) ++ # Compilation has to be from stdin to avoid the temporary file ++ # name being written into the generated dependencies. ++ cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name)) ++ subprocess.check_call(cmd, shell=True) ++ consts = {} ++ with open(s_file_name, 'r') as s_file: ++ for line in s_file: ++ match = re.search('@@@name@@@([^@]*)' ++ '@@@value@@@[^0-9Xxa-fA-F-]*' ++ '([0-9Xxa-fA-F-]+).*@@@end@@@', line) ++ if match: ++ if (match.group(1) in consts ++ and match.group(2) != consts[match.group(1)]): ++ raise ValueError('duplicate constant %s' ++ % match.group(1)) ++ consts[match.group(1)] = match.group(2) ++ return consts ++ ++ ++def list_macros(source_text, cc): ++ """List the preprocessor macros defined by the given source code. ++ ++ The return value is a pair of dicts, the first one mapping macro ++ names to their expansions and the second one mapping macro names ++ to lists of their arguments, or to None for object-like macros. ++ ++ """ ++ with tempfile.TemporaryDirectory() as temp_dir: ++ c_file_name = os.path.join(temp_dir, 'test.c') ++ i_file_name = os.path.join(temp_dir, 'test.i') ++ with open(c_file_name, 'w') as c_file: ++ c_file.write(source_text) ++ cmd = ('%s -E -dM -o %s %s' % (cc, i_file_name, c_file_name)) ++ subprocess.check_call(cmd, shell=True) ++ macros_exp = {} ++ macros_args = {} ++ with open(i_file_name, 'r') as i_file: ++ for line in i_file: ++ match = re.fullmatch('#define ([0-9A-Za-z_]+)(.*)\n', line) ++ if not match: ++ raise ValueError('bad -dM output line: %s' % line) ++ name = match.group(1) ++ value = match.group(2) ++ if value.startswith(' '): ++ value = value[1:] ++ args = None ++ elif value.startswith('('): ++ match = re.fullmatch(r'\((.*?)\) (.*)', value) ++ if not match: ++ raise ValueError('bad -dM output line: %s' % line) ++ args = match.group(1).split(',') ++ value = match.group(2) ++ else: ++ raise ValueError('bad -dM output line: %s' % line) ++ if name in macros_exp: ++ raise ValueError('duplicate macro: %s' % line) ++ macros_exp[name] = value ++ macros_args[name] = args ++ return macros_exp, macros_args ++ ++ ++def compute_macro_consts(source_text, cc, macro_re, exclude_re=None): ++ """Compute the integer constant values of macros defined by source_text. ++ ++ Macros must match the regular expression macro_re, and if ++ exclude_re is defined they must not match exclude_re. Values are ++ computed with compute_c_consts. ++ ++ """ ++ macros_exp, macros_args = list_macros(source_text, cc) ++ macros_set = {m for m in macros_exp ++ if (macros_args[m] is None ++ and re.fullmatch(macro_re, m) ++ and (exclude_re is None ++ or not re.fullmatch(exclude_re, m)))} ++ sym_data = [source_text, 'START'] ++ sym_data.extend(sorted((m, m) for m in macros_set)) ++ return compute_c_consts(sym_data, cc) ++ ++ ++def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None): ++ """Compare the values of macros defined by two different sources. ++ ++ The sources would typically be includes of a glibc header and a ++ kernel header. Return 1 if there were any differences, 0 if the ++ macro values were the same. ++ ++ """ ++ macros_1 = compute_macro_consts(source_1, cc, macro_re, exclude_re) ++ macros_2 = compute_macro_consts(source_2, cc, macro_re, exclude_re) ++ if macros_1 == macros_2: ++ return 0 ++ print('First source:\n%s\n' % source_1) ++ print('Second source:\n%s\n' % source_2) ++ for name, value in sorted(macros_1.items()): ++ if name not in macros_2: ++ print('Only in first source: %s' % name) ++ elif macros_1[name] != macros_2[name]: ++ print('Different values for %s: %s != %s' ++ % (name, macros_1[name], macros_2[name])) ++ for name in sorted(macros_2.keys()): ++ if name not in macros_1: ++ print('Only in second source: %s' % name) ++ return 1 +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index bb055f9d6b841ff5..9c10ee53b26e1b1b 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -113,11 +113,14 @@ tests-special += $(objpfx)tst-signal-numbers.out + # in this context, but signal.c includes signal.h and not much else so it'll + # be conservatively correct. + $(objpfx)tst-signal-numbers.out: \ +- ../sysdeps/unix/sysv/linux/tst-signal-numbers.sh \ ++ ../sysdeps/unix/sysv/linux/tst-signal-numbers.py \ + $(objpfx)signal.o* +- AWK=$(AWK) $(SHELL) ../sysdeps/unix/sysv/linux/tst-signal-numbers.sh \ +- $(CC) $(patsubst -DMODULE_NAME=%,-DMODULE_NAME=testsuite,$(CPPFLAGS)) \ +- < /dev/null > $@; $(evaluate-test) ++ PYTHONPATH=../scripts \ ++ $(PYTHON) ../sysdeps/unix/sysv/linux/tst-signal-numbers.py \ ++ --cc="$(CC) $(patsubst -DMODULE_NAME=%, \ ++ -DMODULE_NAME=testsuite, \ ++ $(CPPFLAGS))" \ ++ < /dev/null > $@ 2>&1; $(evaluate-test) + endif + + ifeq ($(subdir),socket) +diff --git a/sysdeps/unix/sysv/linux/tst-signal-numbers.py b/sysdeps/unix/sysv/linux/tst-signal-numbers.py +new file mode 100644 +index 0000000000000000..48c63d1218e8303d +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-signal-numbers.py +@@ -0,0 +1,48 @@ ++#!/usr/bin/python3 ++# Test that glibc's signal numbers match the kernel's. ++# Copyright (C) 2018 Free Software Foundation, Inc. ++# This file is part of the GNU C Library. ++# ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++# ++# The GNU C Library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# . ++ ++import argparse ++import sys ++ ++import glibcextract ++ ++ ++def main(): ++ """The main entry point.""" ++ parser = argparse.ArgumentParser( ++ description="Test that glibc's signal numbers match the kernel's.") ++ parser.add_argument('--cc', metavar='CC', ++ help='C compiler (including options) to use') ++ args = parser.parse_args() ++ sys.exit(glibcextract.compare_macro_consts( ++ '#define _GNU_SOURCE 1\n' ++ '#include \n', ++ '#define _GNU_SOURCE 1\n' ++ '#include \n' ++ '#include \n', ++ args.cc, ++ # Filter out constants that aren't signal numbers. ++ 'SIG[A-Z]+', ++ # Discard obsolete signal numbers and unrelated constants: ++ # SIGCLD, SIGIOT, SIGSWI, SIGUNUSED. ++ # SIGSTKSZ, SIGRTMIN, SIGRTMAX. ++ 'SIG(CLD|IOT|RT(MIN|MAX)|STKSZ|SWI|UNUSED)')) ++ ++if __name__ == '__main__': ++ main() +diff --git a/sysdeps/unix/sysv/linux/tst-signal-numbers.sh b/sysdeps/unix/sysv/linux/tst-signal-numbers.sh +deleted file mode 100644 +index e1f7be0337c720a6..0000000000000000 +--- a/sysdeps/unix/sysv/linux/tst-signal-numbers.sh ++++ /dev/null +@@ -1,86 +0,0 @@ +-#! /bin/sh +-# Test that glibc's signal numbers match the kernel's. +-# Copyright (C) 2017-2018 Free Software Foundation, Inc. +-# This file is part of the GNU C Library. +- +-# The GNU C Library is free software; you can redistribute it and/or +-# modify it under the terms of the GNU Lesser General Public +-# License as published by the Free Software Foundation; either +-# version 2.1 of the License, or (at your option) any later version. +- +-# The GNU C Library is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-# Lesser General Public License for more details. +- +-# You should have received a copy of the GNU Lesser General Public +-# License along with the GNU C Library; if not, see +-# . +- +-set -e +-if [ -n "$BASH_VERSION" ]; then set -o pipefail; fi +-LC_ALL=C; export LC_ALL +- +-# We cannot use Linux's asm/signal.h to define signal numbers, because +-# it isn't sufficiently namespace-clean. Instead, this test checks +-# that our signal numbers match the kernel's. This script expects +-# "$@" to be $(CC) $(CPPFLAGS) as set by glibc's Makefiles, and $AWK +-# to be set in the environment. +- +-# Before doing anything else, fail if the compiler doesn't work. +-"$@" -E -xc -dM - < /dev/null > /dev/null +- +-tmpG=`mktemp -t signums_glibc.XXXXXXXXX` +-tmpK=`mktemp -t signums_kernel.XXXXXXXXX` +-trap "rm -f '$tmpG' '$tmpK'" 0 +- +-# Filter out constants that aren't signal numbers. +-# If SIGPOLL is defined as SIGIO, swap it around so SIGIO is defined as +-# SIGPOLL. Similarly for SIGABRT and SIGIOT. +-# Discard obsolete signal numbers and unrelated constants: +-# SIGCLD, SIGIOT, SIGSWI, SIGUNUSED. +-# SIGSTKSZ, SIGRTMIN, SIGRTMAX. +-# Then sort the list. +-filter_defines () +-{ +- $AWK ' +-/^#define SIG[A-Z]+ ([0-9]+|SIG[A-Z0-9]+)$/ { signals[$2] = $3 } +-END { +- if ("SIGPOLL" in signals && "SIGIO" in signals && +- signals["SIGPOLL"] == "SIGIO") { +- signals["SIGPOLL"] = signals["SIGIO"] +- signals["SIGIO"] = "SIGPOLL" +- } +- if ("SIGABRT" in signals && "SIGIOT" in signals && +- signals["SIGABRT"] == "SIGIOT") { +- signals["SIGABRT"] = signals["SIGIOT"] +- signals["SIGIOT"] = "SIGABRT" +- } +- for (sig in signals) { +- if (sig !~ /^SIG(CLD|IOT|RT(MIN|MAX)|STKSZ|SWI|UNUSED)$/) { +- printf("#define %s %s\n", sig, signals[sig]) +- } +- } +-}' | sort +-} +- +-# $CC may contain command-line switches, so it should be word-split. +-printf '%s' '#define _GNU_SOURCE 1 +-#include +-' | +- "$@" -E -xc -dM - | +- filter_defines > "$tmpG" +- +-printf '%s' '#define _GNU_SOURCE 1 +-#define __ASSEMBLER__ 1 +-#include +-' | +- "$@" -E -xc -dM - | +- filter_defines > "$tmpK" +- +-if cmp -s "$tmpG" "$tmpK"; then +- exit 0 +-else +- diff -u "$tmpG" "$tmpK" +- exit 1 +-fi diff --git a/glibc-rh2109510-6.patch b/glibc-rh2109510-6.patch new file mode 100644 index 0000000..61251dc --- /dev/null +++ b/glibc-rh2109510-6.patch @@ -0,0 +1,98 @@ +Partial backport of: + +commit cb7be1590e9b18e272e72eb4e910a7ad06a53bd0 +Author: Joseph Myers +Date: Mon Dec 10 22:56:59 2018 +0000 + + Use gen-as-const.py to process .pysym files. + + This patch eliminates the gen-py-const.awk variant of gen-as-const, + switching to use of gnu-as-const.py (with a new --python option) to + process .pysym files (i.e., to generate nptl_lock_constants.py), as + the syntax of those files is identical to that of .sym files. + + Note that the generated nptl_lock_constants.py is *not* identical to + the version generated by the awk script. Apart from the trivial + changes (comment referencing the new script, and output being sorted), + the constant FUTEX_WAITERS, PTHREAD_MUTEXATTR_FLAG_BITS, + PTHREAD_MUTEXATTR_FLAG_PSHARED and PTHREAD_MUTEX_PRIO_CEILING_MASK are + now output as positive rather than negative constants (on x86_64 + anyway; maybe not necessarily on 32-bit systems): + + < FUTEX_WAITERS = -2147483648 + --- + > FUTEX_WAITERS = 2147483648 + + < PTHREAD_MUTEXATTR_FLAG_BITS = -251662336 + < PTHREAD_MUTEXATTR_FLAG_PSHARED = -2147483648 + --- + > PTHREAD_MUTEXATTR_FLAG_BITS = 4043304960 + > PTHREAD_MUTEXATTR_FLAG_PSHARED = 2147483648 + + < PTHREAD_MUTEX_PRIO_CEILING_MASK = -524288 + --- + > PTHREAD_MUTEX_PRIO_CEILING_MASK = 4294443008 + + This is because gen-as-const has a cast of the constant value to long + int, which gen-py-const lacks. + + I think the positive values are more logically correct, since the + constants in question are in fact unsigned in C. But to reliably + produce gen-as-const.py output for constants that always (in C and + Python) reflects the signedness of values with the high bit of "long + int" set would mean more complicated logic needs to be used in + computing values. + + The more correct positive values by themselves produce a failure of + nptl/test-mutexattr-printers, because masking with + ~PTHREAD_MUTEXATTR_FLAG_BITS & ~PTHREAD_MUTEX_NO_ELISION_NP now leaves + a bit -1 << 32 in the Python value, resulting in a KeyError exception. + To avoid that, places masking with ~ of one of the constants in + question are changed to mask with 0xffffffff as well (this reflects + how ~ in Python applies to an infinite-precision integer whereas ~ in + C does not do any promotions beyond the width of int). + + Tested for x86_64. + + * scripts/gen-as-const.py (main): Handle --python option. + * scripts/gen-py-const.awk: Remove. + * Makerules (py-const-script): Use gen-as-const.py. + ($(py-const)): Likewise. + * nptl/nptl-printers.py (MutexPrinter.read_status_no_robust): Mask + with 0xffffffff together with ~(PTHREAD_MUTEX_PRIO_CEILING_MASK). + (MutexAttributesPrinter.read_values): Mask with 0xffffffff + together with ~PTHREAD_MUTEXATTR_FLAG_BITS and + ~PTHREAD_MUTEX_NO_ELISION_NP. + * manual/README.pretty-printers: Update reference to + gen-py-const.awk. + +Only the gen-as-const.py changes are included downstream. We keep using +gen-py-const.awk for the build. + +diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py +index f85e359394acb1a4..2f1dff092b98e044 100644 +--- a/scripts/gen-as-const.py ++++ b/scripts/gen-as-const.py +@@ -75,6 +75,8 @@ def main(): + help='C compiler (including options) to use') + parser.add_argument('--test', action='store_true', + help='Generate test case instead of header') ++ parser.add_argument('--python', action='store_true', ++ help='Generate Python file instead of header') + parser.add_argument('sym_file', + help='.sym file to process') + args = parser.parse_args() +@@ -103,6 +105,13 @@ def main(): + sym_data.append('START') + if args.test: + print(gen_test(sym_data)) ++ elif args.python: ++ consts = glibcextract.compute_c_consts(sym_data, args.cc) ++ print('# GENERATED FILE\n' ++ '\n' ++ '# Constant definitions.\n' ++ '# See gen-as-const.py for details.\n') ++ print(''.join('%s = %s\n' % c for c in sorted(consts.items())), end='') + else: + consts = glibcextract.compute_c_consts(sym_data, args.cc) + print(''.join('#define %s %s\n' % c for c in sorted(consts.items())), end='') diff --git a/glibc-rh2109510-7.patch b/glibc-rh2109510-7.patch new file mode 100644 index 0000000..3da8337 --- /dev/null +++ b/glibc-rh2109510-7.patch @@ -0,0 +1,178 @@ +commit df648905e7d8340bb3e78813fd25e2077b9685d9 +Author: Joseph Myers +Date: Mon Dec 17 18:29:36 2018 +0000 + + Add test that MAP_* constants agree with kernel. + + Continuing the process of building up and using Python infrastructure + for extracting and using values in headers, this patch adds a test + that MAP_* constants from sys/mman.h agree with those in the Linux + kernel headers. (Other sys/mman.h constants could be added to the + test separately.) + + This set of constants has grown over time, so the generic code is + enhanced to allow saying extra constants are OK on either side of the + comparison (where the caller sets those parameters based on the Linux + kernel headers version, compared with the version the headers were + last updated from). Although the test is a custom Python file, my + intention is to move in future to a single Python script for such + tests and text files it takes as inputs, once there are enough + examples to provide a guide to the common cases in such tests (I'd + like to end up with most or all such sets of constants copied from + kernel headers having such tests, and likewise for structure layouts + from the kernel). + + The Makefile code is essentially the same as for tst-signal-numbers, + but I didn't try to find an object file to depend on to represent the + dependency on the headers used by the test (the conform/ tests don't + try to represent such header dependencies at all, for example). + + Tested with build-many-glibcs.py, and also for x86_64 with older + kernel headers. + + * scripts/glibcextract.py (compare_macro_consts): Take parameters + to allow extra macros from first or second sources. + * sysdeps/unix/sysv/linux/tst-mman-consts.py: New file. + * sysdeps/unix/sysv/linux/Makefile [$(subdir) = misc] + (tests-special): Add $(objpfx)tst-mman-consts.out. + ($(objpfx)tst-mman-consts.out): New makefile target. + +diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py +index ecc4d5b6cc387c7d..06f712ad115e0f9e 100644 +--- a/scripts/glibcextract.py ++++ b/scripts/glibcextract.py +@@ -136,12 +136,19 @@ def compute_macro_consts(source_text, cc, macro_re, exclude_re=None): + return compute_c_consts(sym_data, cc) + + +-def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None): ++def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None, ++ allow_extra_1=False, allow_extra_2=False): + """Compare the values of macros defined by two different sources. + + The sources would typically be includes of a glibc header and a +- kernel header. Return 1 if there were any differences, 0 if the +- macro values were the same. ++ kernel header. If allow_extra_1, the first source may define ++ extra macros (typically if the kernel headers are older than the ++ version glibc has taken definitions from); if allow_extra_2, the ++ second source may define extra macros (typically if the kernel ++ headers are newer than the version glibc has taken definitions ++ from). Return 1 if there were any differences other than those ++ allowed, 0 if the macro values were the same apart from any ++ allowed differences. + + """ + macros_1 = compute_macro_consts(source_1, cc, macro_re, exclude_re) +@@ -150,13 +157,19 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None): + return 0 + print('First source:\n%s\n' % source_1) + print('Second source:\n%s\n' % source_2) ++ ret = 0 + for name, value in sorted(macros_1.items()): + if name not in macros_2: + print('Only in first source: %s' % name) ++ if not allow_extra_1: ++ ret = 1 + elif macros_1[name] != macros_2[name]: + print('Different values for %s: %s != %s' + % (name, macros_1[name], macros_2[name])) ++ ret = 1 + for name in sorted(macros_2.keys()): + if name not in macros_1: + print('Only in second source: %s' % name) +- return 1 ++ if not allow_extra_2: ++ ret = 1 ++ return ret +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 9c10ee53b26e1b1b..863ed80c2a2713d3 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -98,6 +98,15 @@ $(objpfx)tst-sysconf-iov_max: $(objpfx)tst-sysconf-iov_max-uapi.o + + $(objpfx)tst-pkey: $(shared-thread-library) + ++tests-special += $(objpfx)tst-mman-consts.out ++$(objpfx)tst-mman-consts.out: ../sysdeps/unix/sysv/linux/tst-mman-consts.py ++ PYTHONPATH=../scripts \ ++ $(PYTHON) ../sysdeps/unix/sysv/linux/tst-mman-consts.py \ ++ --cc="$(CC) $(patsubst -DMODULE_NAME=%, \ ++ -DMODULE_NAME=testsuite, \ ++ $(CPPFLAGS))" \ ++ < /dev/null > $@ 2>&1; $(evaluate-test) ++ + endif # $(subdir) == misc + + ifeq ($(subdir),time) +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +new file mode 100644 +index 0000000000000000..1a613beec0da16fb +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -0,0 +1,65 @@ ++#!/usr/bin/python3 ++# Test that glibc's sys/mman.h constants match the kernel's. ++# Copyright (C) 2018 Free Software Foundation, Inc. ++# This file is part of the GNU C Library. ++# ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++# ++# The GNU C Library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# . ++ ++import argparse ++import sys ++ ++import glibcextract ++ ++ ++def linux_kernel_version(cc): ++ """Return the (major, minor) version of the Linux kernel headers.""" ++ sym_data = ['#include ', 'START', ++ ('LINUX_VERSION_CODE', 'LINUX_VERSION_CODE')] ++ val = glibcextract.compute_c_consts(sym_data, cc)['LINUX_VERSION_CODE'] ++ val = int(val) ++ return ((val & 0xff0000) >> 16, (val & 0xff00) >> 8) ++ ++ ++def main(): ++ """The main entry point.""" ++ parser = argparse.ArgumentParser( ++ description="Test that glibc's sys/mman.h constants " ++ "match the kernel's.") ++ parser.add_argument('--cc', metavar='CC', ++ help='C compiler (including options) to use') ++ args = parser.parse_args() ++ linux_version_headers = linux_kernel_version(args.cc) ++ linux_version_glibc = (4, 19) ++ sys.exit(glibcextract.compare_macro_consts( ++ '#define _GNU_SOURCE 1\n' ++ '#include \n', ++ '#define _GNU_SOURCE 1\n' ++ '#include \n', ++ args.cc, ++ 'MAP_.*', ++ # A series of MAP_HUGE_ macros are defined by the kernel ++ # but not by glibc. MAP_UNINITIALIZED is kernel-only. ++ # MAP_FAILED is not a MAP_* flag and is glibc-only, as is the ++ # MAP_ANON alias for MAP_ANONYMOUS. MAP_RENAME, MAP_AUTOGROW, ++ # MAP_LOCAL and MAP_AUTORSRV are in the kernel header for ++ # MIPS, marked as "not used by linux"; SPARC has MAP_INHERIT ++ # in the kernel header, but does not use it. ++ 'MAP_HUGE_[0-9].*|MAP_UNINITIALIZED|MAP_FAILED|MAP_ANON' ++ '|MAP_RENAME|MAP_AUTOGROW|MAP_LOCAL|MAP_AUTORSRV|MAP_INHERIT', ++ linux_version_glibc > linux_version_headers, ++ linux_version_headers > linux_version_glibc)) ++ ++if __name__ == '__main__': ++ main() diff --git a/glibc-rh2109510-8.patch b/glibc-rh2109510-8.patch new file mode 100644 index 0000000..120abed --- /dev/null +++ b/glibc-rh2109510-8.patch @@ -0,0 +1,23 @@ +commit 46baeb61e16511f26db1b255e19dc9163f590367 +Author: Fangrui Song +Date: Tue Oct 19 09:58:16 2021 -0700 + + glibcextract.py: Place un-assemblable @@@ in a comment + + Unlike GCC, Clang parses asm statements and verifies they are valid + instructions/directives. Place the magic @@@ into a comment to avoid + a parse error. + +diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py +index 06f712ad115e0f9e..8f2246aae6a9dfb7 100644 +--- a/scripts/glibcextract.py ++++ b/scripts/glibcextract.py +@@ -45,7 +45,7 @@ def compute_c_consts(sym_data, cc): + continue + name = arg[0] + value = arg[1] +- out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" ' ++ out_lines.append('asm ("/* @@@name@@@%s@@@value@@@%%0@@@end@@@ */" ' + ': : \"i\" ((long int) (%s)));' + % (name, value)) + out_lines.append('}') diff --git a/glibc-rh2109510-9.patch b/glibc-rh2109510-9.patch new file mode 100644 index 0000000..289f6df --- /dev/null +++ b/glibc-rh2109510-9.patch @@ -0,0 +1,45 @@ +commit 841afa116e32b3c7195475769c26bf46fd870d32 +Author: Adhemerval Zanella +Date: Wed Aug 10 16:24:06 2022 -0300 + + glibcextract.py: Add compile_c_snippet + + It might be used on tests to check if a snippet build with the provided + compiler and flags. + + Reviewed-by: Florian Weimer + +diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py +index 8f2246aae6a9dfb7..0fb50dc8f9c4f7f9 100644 +--- a/scripts/glibcextract.py ++++ b/scripts/glibcextract.py +@@ -17,6 +17,7 @@ + # License along with the GNU C Library; if not, see + # . + ++import collections + import os.path + import re + import subprocess +@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None, + if not allow_extra_2: + ret = 1 + return ret ++ ++CompileResult = collections.namedtuple("CompileResult", "returncode output") ++ ++def compile_c_snippet(snippet, cc, extra_cc_args=''): ++ """Compile and return whether the SNIPPET can be build with CC along ++ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE ++ being 0 for success, or the failure value and the compiler output. ++ """ ++ with tempfile.TemporaryDirectory() as temp_dir: ++ c_file_name = os.path.join(temp_dir, 'test.c') ++ obj_file_name = os.path.join(temp_dir, 'test.o') ++ with open(c_file_name, 'w') as c_file: ++ c_file.write(snippet + '\n') ++ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name, ++ c_file_name] ++ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT) ++ return CompileResult(r.returncode, r.stdout) diff --git a/glibc-rh2116938.patch b/glibc-rh2116938.patch new file mode 100644 index 0000000..f642aba --- /dev/null +++ b/glibc-rh2116938.patch @@ -0,0 +1,449 @@ +1. Added "$(objpfx)tst-cmsghdr: $(libdl)" to socket/Makefile since we still + need $(libdl) in RHEL8. + +2. Included stddef.h in socket/tst-cmsghdr-skeleton.c because it uses NULL. + +commit 9c443ac4559a47ed99859bd80d14dc4b6dd220a1 +Author: Arjun Shankar +Date: Tue Aug 2 11:10:25 2022 +0200 + + socket: Check lengths before advancing pointer in CMSG_NXTHDR + + The inline and library functions that the CMSG_NXTHDR macro may expand + to increment the pointer to the header before checking the stride of + the increment against available space. Since C only allows incrementing + pointers to one past the end of an array, the increment must be done + after a length check. This commit fixes that and includes a regression + test for CMSG_FIRSTHDR and CMSG_NXTHDR. + + The Linux, Hurd, and generic headers are all changed. + + Tested on Linux on armv7hl, i686, x86_64, aarch64, ppc64le, and s390x. + + [BZ #28846] + + Reviewed-by: Siddhesh Poyarekar + +Conflicts: + socket/Makefile + (usual test backport differences) + +diff --git a/bits/socket.h b/bits/socket.h +index 725798882e4b803b..0474613a9c003eeb 100644 +--- a/bits/socket.h ++++ b/bits/socket.h +@@ -245,6 +245,12 @@ struct cmsghdr + + CMSG_ALIGN (sizeof (struct cmsghdr))) + #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + ++/* Given a length, return the additional padding necessary such that ++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ ++#define __CMSG_PADDING(len) ((sizeof (size_t) \ ++ - ((len) & (sizeof (size_t) - 1))) \ ++ & (sizeof (size_t) - 1)) ++ + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + struct cmsghdr *__cmsg) __THROW; + #ifdef __USE_EXTERN_INLINES +@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + _EXTERN_INLINE struct cmsghdr * + __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) + { ++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and ++ __mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of __cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; ++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; ++ ++ size_t __size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (__cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ + return (struct cmsghdr *) 0; + ++ /* There isn't enough space between __cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) ++ < __size_needed) ++ || ((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr ++ - __size_needed) ++ < __cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; ++ ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); +- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control +- + __mhdr->msg_controllen) +- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) +- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) +- /* No more entries. */ +- return (struct cmsghdr *) 0; + return __cmsg; + } + #endif /* Use `extern inline'. */ +diff --git a/socket/Makefile b/socket/Makefile +index 8975a65c2aabbfbc..a445383f8739351e 100644 +--- a/socket/Makefile ++++ b/socket/Makefile +@@ -31,7 +31,12 @@ routines := accept bind connect getpeername getsockname getsockopt \ + setsockopt shutdown socket socketpair isfdtype opensock \ + sockatmark accept4 recvmmsg sendmmsg sockaddr_un_set + +-tests := tst-accept4 ++tests := \ ++ tst-accept4 \ ++ tst-cmsghdr \ ++ # tests ++ ++$(objpfx)tst-cmsghdr: $(libdl) + + tests-internal := \ + tst-sockaddr_un_set \ +diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c +new file mode 100644 +index 0000000000000000..7accfa6e54708e2a +--- /dev/null ++++ b/socket/tst-cmsghdr-skeleton.c +@@ -0,0 +1,93 @@ ++/* Test ancillary data header creation. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* We use the preprocessor to generate the function/macro tests instead of ++ using indirection because having all the macro expansions alongside ++ each other lets the compiler warn us about suspicious pointer ++ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */ ++ ++#include ++#include ++ ++#define RUN_TEST_CONCAT(suffix) run_test_##suffix ++#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix) ++ ++static void ++RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void) ++{ ++ struct msghdr m = {0}; ++ struct cmsghdr *cmsg; ++ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0}; ++ ++ m.msg_control = cmsgbuf; ++ m.msg_controllen = sizeof (cmsgbuf); ++ ++ /* First header should point to the start of the buffer. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ ++ /* If the first header length consumes the entire buffer, there is no ++ space remaining for additional headers. */ ++ cmsg->cmsg_len = sizeof (cmsgbuf); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ /* The first header length is so big, using it would cause an overflow. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len = SIZE_MAX; ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ /* The first header leaves just enough space to hold another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ ++ /* The first header leaves space but not enough for another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len ++; ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ /* The second header leaves just enough space to hold another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD)); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ cmsg->cmsg_len = sizeof (cmsgbuf) ++ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */ ++ - sizeof (struct cmsghdr); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ ++ /* The second header leaves space but not enough for another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ cmsg->cmsg_len ++; ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ return; ++} +diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c +new file mode 100644 +index 0000000000000000..68c96d3c9dd2bce8 +--- /dev/null ++++ b/socket/tst-cmsghdr.c +@@ -0,0 +1,56 @@ ++/* Test ancillary data header creation. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#define PAYLOAD "Hello, World!" ++ ++/* CMSG_NXTHDR is a macro that calls an inline function defined in ++ bits/socket.h. In case the function cannot be inlined, libc.so carries ++ a copy. Both versions need to be tested. */ ++ ++#define CMSG_NXTHDR_IMPL CMSG_NXTHDR ++#include "tst-cmsghdr-skeleton.c" ++#undef CMSG_NXTHDR_IMPL ++ ++static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *); ++ ++#define CMSG_NXTHDR_IMPL cmsg_nxthdr ++#include "tst-cmsghdr-skeleton.c" ++#undef CMSG_NXTHDR_IMPL ++ ++static int ++do_test (void) ++{ ++ static void *handle; ++ ++ run_test_CMSG_NXTHDR (); ++ ++ handle = xdlopen (LIBC_SO, RTLD_LAZY); ++ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *)) ++ xdlsym (handle, "__cmsg_nxthdr"); ++ ++ run_test_cmsg_nxthdr (); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h +index 18959139dc7d325b..cc66684061e3e179 100644 +--- a/sysdeps/mach/hurd/bits/socket.h ++++ b/sysdeps/mach/hurd/bits/socket.h +@@ -249,6 +249,12 @@ struct cmsghdr + + CMSG_ALIGN (sizeof (struct cmsghdr))) + #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + ++/* Given a length, return the additional padding necessary such that ++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ ++#define __CMSG_PADDING(len) ((sizeof (size_t) \ ++ - ((len) & (sizeof (size_t) - 1))) \ ++ & (sizeof (size_t) - 1)) ++ + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + struct cmsghdr *__cmsg) __THROW; + #ifdef __USE_EXTERN_INLINES +@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + _EXTERN_INLINE struct cmsghdr * + __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) + { ++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and ++ __mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of __cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; ++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; ++ ++ size_t __size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (__cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ + return (struct cmsghdr *) 0; + ++ /* There isn't enough space between __cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) ++ < __size_needed) ++ || ((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr ++ - __size_needed) ++ < __cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; ++ ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); +- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control +- + __mhdr->msg_controllen) +- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) +- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) +- /* No more entries. */ +- return (struct cmsghdr *) 0; + return __cmsg; + } + #endif /* Use `extern inline'. */ +diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h +index c3fbb2110296273c..6b895b89831d2cb5 100644 +--- a/sysdeps/unix/sysv/linux/bits/socket.h ++++ b/sysdeps/unix/sysv/linux/bits/socket.h +@@ -302,6 +302,12 @@ struct cmsghdr + + CMSG_ALIGN (sizeof (struct cmsghdr))) + #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + ++/* Given a length, return the additional padding necessary such that ++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ ++#define __CMSG_PADDING(len) ((sizeof (size_t) \ ++ - ((len) & (sizeof (size_t) - 1))) \ ++ & (sizeof (size_t) - 1)) ++ + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + struct cmsghdr *__cmsg) __THROW; + #ifdef __USE_EXTERN_INLINES +@@ -311,18 +317,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + _EXTERN_INLINE struct cmsghdr * + __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) + { ++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and ++ __mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of __cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; ++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; ++ ++ size_t __size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (__cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ + return (struct cmsghdr *) 0; + ++ /* There isn't enough space between __cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) ++ < __size_needed) ++ || ((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr ++ - __size_needed) ++ < __cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; ++ ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); +- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control +- + __mhdr->msg_controllen) +- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) +- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) +- /* No more entries. */ +- return (struct cmsghdr *) 0; + return __cmsg; + } + #endif /* Use `extern inline'. */ +diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c +index bab0be6884d9da1c..16594622211c1c8b 100644 +--- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c ++++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c +@@ -23,18 +23,38 @@ + struct cmsghdr * + __cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg) + { ++ /* We may safely assume that cmsg lies between mhdr->msg_control and ++ mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control; ++ unsigned char * cmsg_ptr = (unsigned char *) cmsg; ++ ++ size_t size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ +- return NULL; ++ return (struct cmsghdr *) 0; ++ ++ /* There isn't enough space between cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr) ++ < size_needed) ++ || ((size_t) ++ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr ++ - size_needed) ++ < cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; + ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + cmsg = (struct cmsghdr *) ((unsigned char *) cmsg + + CMSG_ALIGN (cmsg->cmsg_len)); +- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control +- + mhdr->msg_controllen) +- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len) +- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen))) +- /* No more entries. */ +- return NULL; + return cmsg; + } + libc_hidden_def (__cmsg_nxthdr) diff --git a/glibc-rh2118667.patch b/glibc-rh2118667.patch new file mode 100644 index 0000000..64f2bcc --- /dev/null +++ b/glibc-rh2118667.patch @@ -0,0 +1,96 @@ +commit dd2315a866a4ac2b838ea1cb10c5ea1c35d51a2f +Author: Florian Weimer +Date: Tue Aug 16 08:27:50 2022 +0200 + + elf: Run tst-audit-tlsdesc, tst-audit-tlsdesc-dlopen everywhere + + The test is valid for all TLS models, but we want to make a reasonable + effort to test the GNU2 model specifically. For example, aarch64 + defaults to GNU2, but does not have -mtls-dialect=gnu2, and the test + was not run there. + + Suggested-by: Martin Coufal + +Conflicts: + elf/Makefile + (missing tst-align3 backport, missing libdl integration) + +diff --git a/elf/Makefile b/elf/Makefile +index 9e721d5d4e0a1cd9..1dd36ba0486e56a0 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -331,6 +331,8 @@ tests += \ + tst-addr1 \ + tst-align \ + tst-align2 \ ++ tst-audit-tlsdesc \ ++ tst-audit-tlsdesc-dlopen \ + tst-audit1 \ + tst-audit11 \ + tst-audit12 \ +@@ -607,6 +609,8 @@ modules-names = \ + tst-alignmod2 \ + tst-array2dep \ + tst-array5dep \ ++ tst-audit-tlsdesc-mod1 \ ++ tst-audit-tlsdesc-mod2 \ + tst-audit11mod1 \ + tst-audit11mod2 \ + tst-audit12mod1 \ +@@ -640,6 +644,7 @@ modules-names = \ + tst-auditmanymod7 \ + tst-auditmanymod8 \ + tst-auditmanymod9 \ ++ tst-auditmod-tlsdesc \ + tst-auditmod1 \ + tst-auditmod9a \ + tst-auditmod9b \ +@@ -809,23 +814,8 @@ modules-names += tst-gnu2-tls1mod + $(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so + tst-gnu2-tls1mod.so-no-z-defs = yes + CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2 ++endif # $(have-mtls-dialect-gnu2) + +-tests += tst-audit-tlsdesc tst-audit-tlsdesc-dlopen +-modules-names += tst-audit-tlsdesc-mod1 tst-audit-tlsdesc-mod2 tst-auditmod-tlsdesc +-$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ +- $(objpfx)tst-audit-tlsdesc-mod2.so \ +- $(shared-thread-library) +-CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2 +-CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2 +-$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) $(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 + tests += tst-protected1a tst-protected1b +@@ -2559,5 +2549,23 @@ $(objpfx)tst-tls21.out: $(objpfx)tst-tls21mod.so + $(objpfx)tst-tls21mod.so: $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so) + + $(objpfx)tst-rtld-run-static.out: $(objpfx)/ldconfig ++ + $(objpfx)tst-dlmopen-gethostbyname: $(libdl) + $(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so ++$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ ++ $(objpfx)tst-audit-tlsdesc-mod2.so \ ++ $(shared-thread-library) ++ifeq (yes,$(have-mtls-dialect-gnu2)) ++# The test is valid for all TLS types, but we want to exercise GNU2 ++# TLS if possible. ++CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2 ++CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2 ++endif ++$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) $(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 diff --git a/glibc-rh2119304-1.patch b/glibc-rh2119304-1.patch new file mode 100644 index 0000000..a76e1bf --- /dev/null +++ b/glibc-rh2119304-1.patch @@ -0,0 +1,49 @@ +Downstream-only patch to move the recently added members (from +glibc-rh2047981-5.patch and glibc-rh2047981-6.patch) to the end +of _rtld_global_ro. This avoids changing the offset of +GLRO (dl_naudit). + +Without this change, the audit invocation loop in the old +__libc_start_main function in a not-yet-updated version of libc.so.6 +reads a non-zero garbage value for GLRO (dl_naudit), assumes that +auditing is active, and reads further garbage pointers, leading to +to a crash. Preserving the old offset of GLRO (dl_naudit) avoids +that. This works because RPM updates /lib64/ld-* before +/lib64/libc.so.6 because it sorts earlier (except on POWER9 due +to the glibc-hwcaps/power9 multilib). + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 9dec9e3d3b6d6aa2..5e56550a4d556fa7 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -648,6 +648,15 @@ struct rtld_global_ro + void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen, + Lmid_t nsid, int argc, char *argv[], char *env[]); + void (*_dl_close) (void *map); ++ void *(*_dl_tls_get_addr_soft) (struct link_map *); ++#ifdef HAVE_DL_DISCOVER_OSVERSION ++ int (*_dl_discover_osversion) (void); ++#endif ++ ++ /* List of auditing interfaces. */ ++ struct audit_ifaces *_dl_audit; ++ unsigned int _dl_naudit; ++ + /* libdl in a secondary namespace (after dlopen) must use + _dl_catch_error from the main namespace, so it has to be + exported in some way. */ +@@ -657,14 +666,6 @@ struct rtld_global_ro + /* libdl in a secondary namespace must use free from the base + namespace. */ + void (*_dl_error_free) (void *); +- void *(*_dl_tls_get_addr_soft) (struct link_map *); +-#ifdef HAVE_DL_DISCOVER_OSVERSION +- int (*_dl_discover_osversion) (void); +-#endif +- +- /* List of auditing interfaces. */ +- struct audit_ifaces *_dl_audit; +- unsigned int _dl_naudit; + }; + # define __rtld_global_attribute__ + # if IS_IN (rtld) diff --git a/glibc-rh2119304-2.patch b/glibc-rh2119304-2.patch new file mode 100644 index 0000000..a1e121b --- /dev/null +++ b/glibc-rh2119304-2.patch @@ -0,0 +1,202 @@ +commit 5ecc98241229d494aaad23a4a3fe106fe11e1f40 +Author: Florian Weimer +Date: Thu Aug 25 16:34:20 2022 +0200 + + s390: Move hwcaps/platform names out of _rtld_global_ro + + Changes to these arrays are often backported to stable releases, + but additions to these arrays shift the offsets of the following + _rltd_global_ro members, thus breaking the GLIBC_PRIVATE ABI. + + Obviously, this change is itself an internal ABI break, but at least + it will avoid further ABI breaks going forward. + + Reviewed-by: Carlos O'Donell + +Conflicts: + sysdeps/s390/Makefile + (missing lazy binding test downstream) + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 5c8e1170b4d799ba..ea453ba87646c95a 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -42,6 +42,10 @@ $(modpfx)gconv-modules-s390.conf: ../sysdeps/s390/gconv-modules-s390.conf \ + cp $< $@ + endif + ++ifeq ($(subdir),elf) ++sysdep-dl-routines += dl-procinfo-s390 ++endif ++ + ifeq ($(subdir),string) + sysdep_routines += bzero memset memset-z900 \ + memcmp memcmp-z900 \ +diff --git a/sysdeps/s390/dl-procinfo-s390.c b/sysdeps/s390/dl-procinfo-s390.c +new file mode 100644 +index 0000000000000000..559f3827936cd017 +--- /dev/null ++++ b/sysdeps/s390/dl-procinfo-s390.c +@@ -0,0 +1,32 @@ ++/* Data for s390 version of processor capability information. ++ Copyright (C) 2006-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 ++ ++const char _dl_s390_cap_flags[_DL_HWCAP_COUNT][9] = ++ { ++ "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh", ++ "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt", ++ "vxp2", "nnpa", "pcimio", "sie" ++ }; ++ ++const char _dl_s390_platforms[_DL_PLATFORMS_COUNT][7] = ++ { ++ "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15", ++ "z16" ++ }; +diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +index 85108943d0e79f29..f928b485609a3b8a 100644 +--- a/sysdeps/s390/dl-procinfo.c ++++ b/sysdeps/s390/dl-procinfo.c +@@ -17,66 +17,10 @@ + License along with the GNU C Library; if not, see + . */ + +-/* This information must be kept in sync with the _DL_HWCAP_COUNT and +- _DL_PLATFORM_COUNT definitions in procinfo.h. +- +- If anything should be added here check whether the size of each string +- is still ok with the given array size. +- +- All the #ifdefs in the definitions are quite irritating but +- necessary if we want to avoid duplicating the information. There +- are three different modes: +- +- - PROCINFO_DECL is defined. This means we are only interested in +- declarations. +- +- - PROCINFO_DECL is not defined: +- +- + if SHARED is defined the file is included in an array +- initializer. The .element = { ... } syntax is needed. +- +- + if SHARED is not defined a normal array initialization is +- needed. +- */ +- +-#ifndef PROCINFO_CLASS +-# define PROCINFO_CLASS +-#endif +- +-#if !defined PROCINFO_DECL && defined SHARED +- ._dl_s390_cap_flags +-#else +-PROCINFO_CLASS const char _dl_s390_cap_flags[23][9] +-#endif +-#ifndef PROCINFO_DECL +-= { +- "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh", +- "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt", +- "vxp2", "nnpa", "pcimio", "sie" +- } +-#endif +-#if !defined SHARED || defined PROCINFO_DECL +-; +-#else +-, +-#endif +- +-#if !defined PROCINFO_DECL && defined SHARED +- ._dl_s390_platforms +-#else +-PROCINFO_CLASS const char _dl_s390_platforms[11][7] +-#endif +-#ifndef PROCINFO_DECL +-= { +- "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15", +- "z16" +- } +-#endif +-#if !defined SHARED || defined PROCINFO_DECL +-; +-#else +-, +-#endif ++/* The hwcap and platform strings are now in ++ sysdeps/s390/dl-procinfo-s390.c. */ + ++/* Needed by sysdeps/unix/sysv/linux/dl-vdso-setup.c (as included from ++ sysdeps/generic/ldsodefs.h). */ + #undef PROCINFO_DECL + #undef PROCINFO_CLASS +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index f2b2c9ac1bb7239b..5eb2c0a39fcff520 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -22,8 +22,10 @@ + #include + + #define _DL_HWCAP_COUNT 23 ++extern const char _dl_s390_cap_flags[_DL_HWCAP_COUNT][9] attribute_hidden; + + #define _DL_PLATFORMS_COUNT 11 ++extern const char _dl_s390_platforms[_DL_PLATFORMS_COUNT][7] attribute_hidden; + + /* The kernel provides up to 32 capability bits with elf_hwcap. */ + #define _DL_FIRST_PLATFORM 32 +@@ -79,7 +81,7 @@ static inline const char * + __attribute__ ((unused)) + _dl_hwcap_string (int idx) + { +- return GLRO(dl_s390_cap_flags)[idx]; ++ return _dl_s390_cap_flags[idx]; + }; + + static inline int +@@ -90,7 +92,7 @@ _dl_string_hwcap (const char *str) + + for (i = 0; i < _DL_HWCAP_COUNT; i++) + { +- if (strcmp (str, GLRO(dl_s390_cap_flags)[i]) == 0) ++ if (strcmp (str, _dl_s390_cap_flags[i]) == 0) + return i; + } + return -1; +@@ -105,7 +107,7 @@ _dl_string_platform (const char *str) + if (str != NULL) + for (i = 0; i < _DL_PLATFORMS_COUNT; ++i) + { +- if (strcmp (str, GLRO(dl_s390_platforms)[i]) == 0) ++ if (strcmp (str, _dl_s390_platforms[i]) == 0) + return _DL_FIRST_PLATFORM + i; + } + return -1; +diff --git a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h +index d1516a05e3042163..4aefd7eef14eaf52 100644 +--- a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h ++++ b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h +@@ -40,7 +40,7 @@ _dl_procinfo (unsigned int type, unsigned long int word) + + for (i = 0; i < _DL_HWCAP_COUNT; ++i) + if (word & (1UL << i)) +- _dl_printf (" %s", GLRO(dl_s390_cap_flags)[i]); ++ _dl_printf (" %s", _dl_s390_cap_flags[i]); + + _dl_printf ("\n"); + diff --git a/glibc-rh2119304-3.patch b/glibc-rh2119304-3.patch new file mode 100644 index 0000000..faaea99 --- /dev/null +++ b/glibc-rh2119304-3.patch @@ -0,0 +1,19 @@ +Downstream-only patch to preserve the 8.6.0 _rtld_global_ro ABI on s390x. + +diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +index f928b485609a3b8a..3f46b2785fafe51e 100644 +--- a/sysdeps/s390/dl-procinfo.c ++++ b/sysdeps/s390/dl-procinfo.c +@@ -20,6 +20,12 @@ + /* The hwcap and platform strings are now in + sysdeps/s390/dl-procinfo-s390.c. */ + ++/* Dummy entries to preserve ABI. */ ++#if defined SHARED && defined PROCINFO_DECL ++const char _dl_s390_cap_flags_unused[23][9]; ++const char _dl_s390_platforms_unused[10][7]; ++#endif ++ + /* Needed by sysdeps/unix/sysv/linux/dl-vdso-setup.c (as included from + sysdeps/generic/ldsodefs.h). */ + #undef PROCINFO_DECL diff --git a/glibc-rh2121746-1.patch b/glibc-rh2121746-1.patch new file mode 100644 index 0000000..a27c0eb --- /dev/null +++ b/glibc-rh2121746-1.patch @@ -0,0 +1,202 @@ +From d0e357ff45a75553dee3b17ed7d303bfa544f6fe Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 26 Aug 2022 21:15:43 +0200 +Subject: elf: Call __libc_early_init for reused namespaces (bug 29528) + +libc_map is never reset to NULL, neither during dlclose nor on a +dlopen call which reuses the namespace structure. As a result, if a +namespace is reused, its libc is not initialized properly. The most +visible result is a crash in the functions. + +To prevent similar bugs on namespace reuse from surfacing, +unconditionally initialize the chosen namespace to zero using memset. + +[Note from DJ: Regenerated for new line numbers and context, added +link dependency on libdl]] + +diff -rupN a/elf/Makefile b/elf/Makefile +--- a/elf/Makefile 2022-10-05 15:04:11.814901849 -0400 ++++ b/elf/Makefile 2022-10-05 17:02:19.858635958 -0400 +@@ -367,6 +367,7 @@ tests += \ + tst-dlmopen3 \ + tst-dlmopen-dlerror \ + tst-dlmopen-gethostbyname \ ++ tst-dlmopen-twice \ + tst-dlopenfail \ + tst-dlopenfail-2 \ + tst-dlopenrpath \ +@@ -671,6 +672,8 @@ modules-names = \ + tst-dlmopen1mod \ + tst-dlmopen-dlerror-mod \ + tst-dlmopen-gethostbyname-mod \ ++ tst-dlmopen-twice-mod1 \ ++ tst-dlmopen-twice-mod2 \ + tst-dlopenfaillinkmod \ + tst-dlopenfailmod1 \ + tst-dlopenfailmod2 \ +@@ -2569,3 +2572,9 @@ $(objpfx)tst-audit-tlsdesc.out: $(objpfx + tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so + $(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so + tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so ++ ++ ++$(objpfx)tst-dlmopen-twice: $(libdl) ++$(objpfx)tst-dlmopen-twice.out: \ ++ $(objpfx)tst-dlmopen-twice-mod1.so \ ++ $(objpfx)tst-dlmopen-twice-mod2.so +diff -rupN a/elf/dl-open.c b/elf/dl-open.c +--- a/elf/dl-open.c 2022-10-05 15:04:11.635894932 -0400 ++++ b/elf/dl-open.c 2022-10-05 15:10:31.667638060 -0400 +@@ -836,11 +836,14 @@ _dl_open (const char *file, int mode, co + _dl_signal_error (EINVAL, file, NULL, N_("\ + no more namespaces available for dlmopen()")); + } +- else if (nsid == GL(dl_nns)) +- { +- __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock); +- ++GL(dl_nns); +- } ++ ++ if (nsid == GL(dl_nns)) ++ ++GL(dl_nns); ++ ++ /* Initialize the new namespace. Most members are ++ zero-initialized, only the lock needs special treatment. */ ++ memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid])); ++ __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock); + + _dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT; + } +diff -rupN a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c +--- a/elf/tst-dlmopen-twice-mod1.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/elf/tst-dlmopen-twice-mod1.c 2022-10-05 15:10:31.671638216 -0400 +@@ -0,0 +1,37 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod1.so loaded"); ++ fflush (stdout); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded"); ++ fflush (stdout); ++} ++ ++/* Large allocation. The second module does not have this, so it ++ should load libc at a different address. */ ++char large_allocate[16 * 1024 * 1024]; +diff -rupN a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c +--- a/elf/tst-dlmopen-twice-mod2.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/elf/tst-dlmopen-twice-mod2.c 2022-10-05 15:10:31.676638411 -0400 +@@ -0,0 +1,50 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod2.so loaded"); ++ fflush (stdout); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded"); ++ fflush (stdout); ++} ++ ++int ++run_check (void) ++{ ++ puts ("info: about to call isalpha"); ++ fflush (stdout); ++ ++ volatile char ch = 'a'; ++ if (!isalpha (ch)) ++ { ++ puts ("error: isalpha ('a') is not true"); ++ fflush (stdout); ++ return 1; ++ } ++ return 0; ++} +diff -rupN a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c +--- a/elf/tst-dlmopen-twice.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/elf/tst-dlmopen-twice.c 2022-10-05 15:10:31.679638528 -0400 +@@ -0,0 +1,34 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW); ++ xdlclose (handle); ++ handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW); ++ int (*run_check) (void) = xdlsym (handle, "run_check"); ++ TEST_COMPARE (run_check (), 0); ++ xdlclose (handle); ++ return 0; ++} ++ ++#include diff --git a/glibc-rh2121746-2.patch b/glibc-rh2121746-2.patch new file mode 100644 index 0000000..5bd43c8 --- /dev/null +++ b/glibc-rh2121746-2.patch @@ -0,0 +1,98 @@ +From 2c42257314536b94cc8d52edede86e94e98c1436 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 14 Oct 2022 11:02:25 +0200 +Subject: [PATCH] elf: Do not completely clear reused namespace in dlmopen (bug + 29600) +Content-type: text/plain; charset=UTF-8 + +The data in the _ns_debug member must be preserved, otherwise +_dl_debug_initialize enters an infinite loop. To be conservative, +only clear the libc_map member for now, to fix bug 29528. + +Fixes commit d0e357ff45a75553dee3b17ed7d303bfa544f6fe +("elf: Call __libc_early_init for reused namespaces (bug 29528)"), +by reverting most of it. + +Reviewed-by: Carlos O'Donell +Tested-by: Carlos O'Donell +--- + elf/dl-open.c | 14 ++++++-------- + elf/tst-dlmopen-twice.c | 28 ++++++++++++++++++++++++---- + 2 files changed, 30 insertions(+), 12 deletions(-) + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 46e8066fd8..e7db5e9642 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -836,15 +836,13 @@ _dl_open (const char *file, int mode, co + _dl_signal_error (EINVAL, file, NULL, N_("\ + no more namespaces available for dlmopen()")); + } ++ else if (nsid == GL(dl_nns)) ++ { ++ __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock); ++ ++GL(dl_nns); ++ } + +- if (nsid == GL(dl_nns)) +- ++GL(dl_nns); +- +- /* Initialize the new namespace. Most members are +- zero-initialized, only the lock needs special treatment. */ +- memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid])); +- __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock); +- ++ GL(dl_ns)[nsid].libc_map = NULL; + _dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT; + } + /* Never allow loading a DSO in a namespace which is empty. Such +diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c +index 449f3c8fa9..70c71fe19c 100644 +--- a/elf/tst-dlmopen-twice.c ++++ b/elf/tst-dlmopen-twice.c +@@ -16,18 +16,38 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include + #include ++#include + +-static int +-do_test (void) ++/* Run the test multiple times, to check finding a new namespace while ++ another namespace is already in use. This used to trigger bug 29600. */ ++static void ++recurse (int depth) + { +- void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW); ++ if (depth == 0) ++ return; ++ ++ printf ("info: running at depth %d\n", depth); ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", ++ RTLD_NOW); + xdlclose (handle); + handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW); + int (*run_check) (void) = xdlsym (handle, "run_check"); + TEST_COMPARE (run_check (), 0); ++ recurse (depth - 1); + xdlclose (handle); ++} ++ ++static int ++do_test (void) ++{ ++ /* First run the test without nesting. */ ++ recurse (1); ++ ++ /* Then with nesting. The constant needs to be less than the ++ internal DL_NNS namespace constant. */ ++ recurse (10); + return 0; + } + +-- +2.31.1 + diff --git a/glibc-rh2122498.patch b/glibc-rh2122498.patch new file mode 100644 index 0000000..1699abf --- /dev/null +++ b/glibc-rh2122498.patch @@ -0,0 +1,39 @@ +commit 02ca25fef2785974011e9c5beecc99b900b69fd7 +Author: Fabian Vogt +Date: Wed Jul 27 11:44:07 2022 +0200 + + nscd: Fix netlink cache invalidation if epoll is used [BZ #29415] + + Processes cache network interface information such as whether IPv4 or IPv6 + are enabled. This is only checked again if the "netlink timestamp" provided + by nscd changed, which is triggered by netlink socket activity. + + However, in the epoll handler for the netlink socket, it was missed to + assign the new timestamp to the nscd database. The handler for plain poll + did that properly, copy that over. + + This bug caused that e.g. processes which started before network + configuration got unusuable addresses from getaddrinfo, like IPv6 only even + though only IPv4 is available: + https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1041 + + It's a bit hard to reproduce, so I verified this by checking the timestamp + on calls to __check_pf manually. Without this patch it's stuck at 1, now + it's increasing on network changes as expected. + + Signed-off-by: Fabian Vogt + +diff --git a/nscd/connections.c b/nscd/connections.c +index 98182007646a33d5..19039bdbb210466a 100644 +--- a/nscd/connections.c ++++ b/nscd/connections.c +@@ -2286,7 +2286,8 @@ main_loop_epoll (int efd) + sizeof (buf))) != -1) + ; + +- __bump_nl_timestamp (); ++ dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP] ++ = __bump_nl_timestamp (); + } + # endif + else diff --git a/glibc-rh2122501-1.patch b/glibc-rh2122501-1.patch new file mode 100644 index 0000000..75d333e --- /dev/null +++ b/glibc-rh2122501-1.patch @@ -0,0 +1,472 @@ +commit c6fad4fa149485a307207f707e5851216f190fc8 +Author: Florian Weimer +Date: Thu Mar 19 18:32:28 2020 -0300 + + stdio: Remove memory leak from multibyte convertion [BZ#25691] + + This is an updated version of a previous patch [1] with the + following changes: + + - Use compiler overflow builtins on done_add_func function. + - Define the scratch +utstring_converted_wide_string using + CHAR_T. + - Added a testcase and mention the bug report. + + Both default and wide printf functions might leak memory when + manipulate multibyte characters conversion depending of the size + of the input (whether __libc_use_alloca trigger or not the fallback + heap allocation). + + This patch fixes it by removing the extra memory allocation on + string formatting with conversion parts. + + The testcase uses input argument size that trigger memory leaks + on unpatched code (using a scratch buffer the threashold to use + heap allocation is lower). + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + Reviewed-by: Adhemerval Zanella + + [1] https://sourceware.org/pipermail/libc-alpha/2017-June/082098.html + + (cherry picked from commit 3cc4a8367c23582b7db14cf4e150e4068b7fd461) + +diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c +index ae412e4b8444aea2..dab56b6ba2c7bdbe 100644 +--- a/stdio-common/vfprintf.c ++++ b/stdio-common/vfprintf.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + /* This code is shared between the standard stdio implementation found + in GNU C library and the libio implementation originally found in +@@ -64,23 +65,40 @@ + } while (0) + #define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED) + +-#define done_add(val) \ +- do { \ +- unsigned int _val = val; \ +- assert ((unsigned int) done < (unsigned int) INT_MAX); \ +- if (__glibc_unlikely (INT_MAX - done < _val)) \ +- { \ +- done = -1; \ +- __set_errno (EOVERFLOW); \ +- goto all_done; \ +- } \ +- done += _val; \ +- } while (0) ++/* Add LENGTH to DONE. Return the new value of DONE, or -1 on ++ overflow (and set errno accordingly). */ ++static inline int ++done_add_func (size_t length, int done) ++{ ++ if (done < 0) ++ return done; ++ int ret; ++ if (INT_ADD_WRAPV (done, length, &ret)) ++ { ++ __set_errno (EOVERFLOW); ++ return -1; ++ } ++ return ret; ++} ++ ++#define done_add(val) \ ++ do \ ++ { \ ++ /* Ensure that VAL has a type similar to int. */ \ ++ _Static_assert (sizeof (val) == sizeof (int), "value int size"); \ ++ _Static_assert ((__typeof__ (val)) -1 < 0, "value signed"); \ ++ done = done_add_func ((val), done); \ ++ if (done < 0) \ ++ goto all_done; \ ++ } \ ++ while (0) + + #ifndef COMPILE_WPRINTF + # define vfprintf _IO_vfprintf_internal + # define CHAR_T char ++# define CHAR_T char + # define UCHAR_T unsigned char ++# define OTHER_CHAR_T wchar_t + # define INT_T int + typedef const char *THOUSANDS_SEP_T; + # define L_(Str) Str +@@ -88,22 +106,10 @@ typedef const char *THOUSANDS_SEP_T; + # define STR_LEN(Str) strlen (Str) + + # define PUT(F, S, N) _IO_sputn ((F), (S), (N)) +-# define PAD(Padchar) \ +- do { \ +- if (width > 0) \ +- { \ +- ssize_t written = _IO_padn (s, (Padchar), width); \ +- if (__glibc_unlikely (written != width)) \ +- { \ +- done = -1; \ +- goto all_done; \ +- } \ +- done_add (written); \ +- } \ +- } while (0) + # define PUTC(C, F) _IO_putc_unlocked (C, F) + # define ORIENT if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\ + return -1 ++# define CONVERT_FROM_OTHER_STRING __wcsrtombs + #else + # define vfprintf _IO_vfwprintf + # define CHAR_T wchar_t +@@ -118,21 +124,11 @@ typedef wchar_t THOUSANDS_SEP_T; + # include <_itowa.h> + + # define PUT(F, S, N) _IO_sputn ((F), (S), (N)) +-# define PAD(Padchar) \ +- do { \ +- if (width > 0) \ +- { \ +- ssize_t written = _IO_wpadn (s, (Padchar), width); \ +- if (__glibc_unlikely (written != width)) \ +- { \ +- done = -1; \ +- goto all_done; \ +- } \ +- done_add (written); \ +- } \ +- } while (0) + # define PUTC(C, F) _IO_putwc_unlocked (C, F) + # define ORIENT if (_IO_fwide (s, 1) != 1) return -1 ++# define CONVERT_FROM_OTHER_STRING __mbsrtowcs ++# define CHAR_T wchar_t ++# define OTHER_CHAR_T char + + # undef _itoa + # define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case) +@@ -141,6 +137,33 @@ typedef wchar_t THOUSANDS_SEP_T; + # define EOF WEOF + #endif + ++static inline int ++pad_func (FILE *s, CHAR_T padchar, int width, int done) ++{ ++ if (width > 0) ++ { ++ ssize_t written; ++#ifndef COMPILE_WPRINTF ++ written = _IO_padn (s, padchar, width); ++#else ++ written = _IO_wpadn (s, padchar, width); ++#endif ++ if (__glibc_unlikely (written != width)) ++ return -1; ++ return done_add_func (width, done); ++ } ++ return done; ++} ++ ++#define PAD(Padchar) \ ++ do \ ++ { \ ++ done = pad_func (s, (Padchar), width, done); \ ++ if (done < 0) \ ++ goto all_done; \ ++ } \ ++ while (0) ++ + #include "_i18n_number.h" + + /* Include the shared code for parsing the format string. */ +@@ -160,24 +183,115 @@ typedef wchar_t THOUSANDS_SEP_T; + } \ + while (0) + +-#define outstring(String, Len) \ +- do \ +- { \ +- assert ((size_t) done <= (size_t) INT_MAX); \ +- if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)) \ +- { \ +- done = -1; \ +- goto all_done; \ +- } \ +- if (__glibc_unlikely (INT_MAX - done < (Len))) \ +- { \ +- done = -1; \ +- __set_errno (EOVERFLOW); \ +- goto all_done; \ +- } \ +- done += (Len); \ +- } \ +- while (0) ++static inline int ++outstring_func (FILE *s, const UCHAR_T *string, size_t length, int done) ++{ ++ assert ((size_t) done <= (size_t) INT_MAX); ++ if ((size_t) PUT (s, string, length) != (size_t) (length)) ++ return -1; ++ return done_add_func (length, done); ++} ++ ++#define outstring(String, Len) \ ++ do \ ++ { \ ++ const void *string_ = (String); \ ++ done = outstring_func (s, string_, (Len), done); \ ++ if (done < 0) \ ++ goto all_done; \ ++ } \ ++ while (0) ++ ++/* Write the string SRC to S. If PREC is non-negative, write at most ++ PREC bytes. If LEFT is true, perform left justification. */ ++static int ++outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec, ++ int width, bool left, int done) ++{ ++ /* Use a small buffer to combine processing of multiple characters. ++ CONVERT_FROM_OTHER_STRING expects the buffer size in (wide) ++ characters, and buf_length counts that. */ ++ enum { buf_length = 256 / sizeof (CHAR_T) }; ++ CHAR_T buf[buf_length]; ++ _Static_assert (sizeof (buf) > MB_LEN_MAX, ++ "buffer is large enough for a single multi-byte character"); ++ ++ /* Add the initial padding if needed. */ ++ if (width > 0 && !left) ++ { ++ /* Make a first pass to find the output width, so that we can ++ add the required padding. */ ++ mbstate_t mbstate = { 0 }; ++ const OTHER_CHAR_T *src_copy = src; ++ size_t total_written; ++ if (prec < 0) ++ total_written = CONVERT_FROM_OTHER_STRING ++ (NULL, &src_copy, 0, &mbstate); ++ else ++ { ++ /* The source might not be null-terminated. Enforce the ++ limit manually, based on the output length. */ ++ total_written = 0; ++ size_t limit = prec; ++ while (limit > 0 && src_copy != NULL) ++ { ++ size_t write_limit = buf_length; ++ if (write_limit > limit) ++ write_limit = limit; ++ size_t written = CONVERT_FROM_OTHER_STRING ++ (buf, &src_copy, write_limit, &mbstate); ++ if (written == (size_t) -1) ++ return -1; ++ if (written == 0) ++ break; ++ total_written += written; ++ limit -= written; ++ } ++ } ++ ++ /* Output initial padding. */ ++ if (total_written < width) ++ { ++ done = pad_func (s, L_(' '), width - total_written, done); ++ if (done < 0) ++ return done; ++ } ++ } ++ ++ /* Convert the input string, piece by piece. */ ++ size_t total_written = 0; ++ { ++ mbstate_t mbstate = { 0 }; ++ /* If prec is negative, remaining is not decremented, otherwise, ++ it serves as the write limit. */ ++ size_t remaining = -1; ++ if (prec >= 0) ++ remaining = prec; ++ while (remaining > 0 && src != NULL) ++ { ++ size_t write_limit = buf_length; ++ if (remaining < write_limit) ++ write_limit = remaining; ++ size_t written = CONVERT_FROM_OTHER_STRING ++ (buf, &src, write_limit, &mbstate); ++ if (written == (size_t) -1) ++ return -1; ++ if (written == 0) ++ break; ++ done = outstring_func (s, (const UCHAR_T *) buf, written, done); ++ if (done < 0) ++ return done; ++ total_written += written; ++ if (prec >= 0) ++ remaining -= written; ++ } ++ } ++ ++ /* Add final padding. */ ++ if (width > 0 && left && total_written < width) ++ return pad_func (s, L_(' '), width - total_written, done); ++ return done; ++} + + /* For handling long_double and longlong we use the same flag. If + `long' and `long long' are effectively the same type define it to +@@ -975,7 +1089,6 @@ static const uint8_t jump_table[] = + LABEL (form_string): \ + { \ + size_t len; \ +- int string_malloced; \ + \ + /* The string argument could in fact be `char *' or `wchar_t *'. \ + But this should not make a difference here. */ \ +@@ -987,7 +1100,6 @@ static const uint8_t jump_table[] = + /* Entry point for printing other strings. */ \ + LABEL (print_string): \ + \ +- string_malloced = 0; \ + if (string == NULL) \ + { \ + /* Write "(null)" if there's space. */ \ +@@ -1004,41 +1116,12 @@ static const uint8_t jump_table[] = + } \ + else if (!is_long && spec != L_('S')) \ + { \ +- /* This is complicated. We have to transform the multibyte \ +- string into a wide character string. */ \ +- const char *mbs = (const char *) string; \ +- mbstate_t mbstate; \ +- \ +- len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \ +- \ +- /* Allocate dynamically an array which definitely is long \ +- enough for the wide character version. Each byte in the \ +- multi-byte string can produce at most one wide character. */ \ +- if (__glibc_unlikely (len > SIZE_MAX / sizeof (wchar_t))) \ +- { \ +- __set_errno (EOVERFLOW); \ +- done = -1; \ +- goto all_done; \ +- } \ +- else if (__libc_use_alloca (len * sizeof (wchar_t))) \ +- string = (CHAR_T *) alloca (len * sizeof (wchar_t)); \ +- else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t))) \ +- == NULL) \ +- { \ +- done = -1; \ +- goto all_done; \ +- } \ +- else \ +- string_malloced = 1; \ +- \ +- memset (&mbstate, '\0', sizeof (mbstate_t)); \ +- len = __mbsrtowcs (string, &mbs, len, &mbstate); \ +- if (len == (size_t) -1) \ +- { \ +- /* Illegal multibyte character. */ \ +- done = -1; \ +- goto all_done; \ +- } \ ++ done = outstring_converted_wide_string \ ++ (s, (const char *) string, prec, width, left, done); \ ++ if (done < 0) \ ++ goto all_done; \ ++ /* The padding has already been written. */ \ ++ break; \ + } \ + else \ + { \ +@@ -1061,8 +1144,6 @@ static const uint8_t jump_table[] = + outstring (string, len); \ + if (left) \ + PAD (L' '); \ +- if (__glibc_unlikely (string_malloced)) \ +- free (string); \ + } \ + break; + #else +@@ -1111,7 +1192,6 @@ static const uint8_t jump_table[] = + LABEL (form_string): \ + { \ + size_t len; \ +- int string_malloced; \ + \ + /* The string argument could in fact be `char *' or `wchar_t *'. \ + But this should not make a difference here. */ \ +@@ -1123,7 +1203,6 @@ static const uint8_t jump_table[] = + /* Entry point for printing other strings. */ \ + LABEL (print_string): \ + \ +- string_malloced = 0; \ + if (string == NULL) \ + { \ + /* Write "(null)" if there's space. */ \ +@@ -1149,51 +1228,12 @@ static const uint8_t jump_table[] = + } \ + else \ + { \ +- const wchar_t *s2 = (const wchar_t *) string; \ +- mbstate_t mbstate; \ +- \ +- memset (&mbstate, '\0', sizeof (mbstate_t)); \ +- \ +- if (prec >= 0) \ +- { \ +- /* The string `s2' might not be NUL terminated. */ \ +- if (__libc_use_alloca (prec)) \ +- string = (char *) alloca (prec); \ +- else if ((string = (char *) malloc (prec)) == NULL) \ +- { \ +- done = -1; \ +- goto all_done; \ +- } \ +- else \ +- string_malloced = 1; \ +- len = __wcsrtombs (string, &s2, prec, &mbstate); \ +- } \ +- else \ +- { \ +- len = __wcsrtombs (NULL, &s2, 0, &mbstate); \ +- if (len != (size_t) -1) \ +- { \ +- assert (__mbsinit (&mbstate)); \ +- s2 = (const wchar_t *) string; \ +- if (__libc_use_alloca (len + 1)) \ +- string = (char *) alloca (len + 1); \ +- else if ((string = (char *) malloc (len + 1)) == NULL) \ +- { \ +- done = -1; \ +- goto all_done; \ +- } \ +- else \ +- string_malloced = 1; \ +- (void) __wcsrtombs (string, &s2, len + 1, &mbstate); \ +- } \ +- } \ +- \ +- if (len == (size_t) -1) \ +- { \ +- /* Illegal wide-character string. */ \ +- done = -1; \ +- goto all_done; \ +- } \ ++ done = outstring_converted_wide_string \ ++ (s, (const wchar_t *) string, prec, width, left, done); \ ++ if (done < 0) \ ++ goto all_done; \ ++ /* The padding has already been written. */ \ ++ break; \ + } \ + \ + if ((width -= len) < 0) \ +@@ -1207,8 +1247,6 @@ static const uint8_t jump_table[] = + outstring (string, len); \ + if (left) \ + PAD (' '); \ +- if (__glibc_unlikely (string_malloced)) \ +- free (string); \ + } \ + break; + #endif diff --git a/glibc-rh2122501-2.patch b/glibc-rh2122501-2.patch new file mode 100644 index 0000000..8cac488 --- /dev/null +++ b/glibc-rh2122501-2.patch @@ -0,0 +1,160 @@ +commit 29b12753b51866b227a6c0ac96c2c6c0e20f3497 +Author: Adhemerval Zanella +Date: Thu Mar 19 18:35:46 2020 -0300 + + stdio: Add tests for printf multibyte convertion leak [BZ#25691] + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + (cherry picked from commit 910a835dc96c1f518ac2a6179fc622ba81ffb159) + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index a10f12ab3ccbd76e..51062a7dbf698931 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -63,6 +63,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ + tst-vfprintf-mbs-prec \ + tst-scanf-round \ + tst-renameat2 \ ++ tst-printf-bz25691 \ + + test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble + +@@ -71,10 +72,12 @@ tests-special += $(objpfx)tst-unbputc.out $(objpfx)tst-printf.out \ + $(objpfx)tst-printf-bz18872-mem.out \ + $(objpfx)tst-setvbuf1-cmp.out \ + $(objpfx)tst-vfprintf-width-prec-mem.out \ +- $(objpfx)tst-printfsz-islongdouble.out ++ $(objpfx)tst-printfsz-islongdouble.out \ ++ $(objpfx)tst-printf-bz25691-mem.out + generated += tst-printf-bz18872.c tst-printf-bz18872.mtrace \ + tst-printf-bz18872-mem.out \ +- tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out ++ tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out \ ++ tst-printf-bz25691.mtrace tst-printf-bz25691-mem.out + endif + + include ../Rules +@@ -96,6 +99,8 @@ endif + tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace + tst-vfprintf-width-prec-ENV = \ + MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace ++tst-printf-bz25691-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace + + $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc + $(SHELL) $< $(common-objpfx) '$(test-program-prefix)' > $@; \ +diff --git a/stdio-common/tst-printf-bz25691.c b/stdio-common/tst-printf-bz25691.c +new file mode 100644 +index 0000000000000000..37b30a3a8a7dc5e2 +--- /dev/null ++++ b/stdio-common/tst-printf-bz25691.c +@@ -0,0 +1,108 @@ ++/* Test for memory leak with large width (BZ#25691). ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ mtrace (); ++ ++ /* For 's' conversion specifier with 'l' modifier the array must be ++ converted to multibyte characters up to the precision specific ++ value. */ ++ { ++ /* The input size value is to force a heap allocation on temporary ++ buffer (in the old implementation). */ ++ const size_t winputsize = 64 * 1024 + 1; ++ wchar_t *winput = xmalloc (winputsize * sizeof (wchar_t)); ++ wmemset (winput, L'a', winputsize - 1); ++ winput[winputsize - 1] = L'\0'; ++ ++ char result[9]; ++ const char expected[] = "aaaaaaaa"; ++ int ret; ++ ++ ret = snprintf (result, sizeof (result), "%.65537ls", winput); ++ TEST_COMPARE (ret, winputsize - 1); ++ TEST_COMPARE_BLOB (result, sizeof (result), expected, sizeof (expected)); ++ ++ ret = snprintf (result, sizeof (result), "%ls", winput); ++ TEST_COMPARE (ret, winputsize - 1); ++ TEST_COMPARE_BLOB (result, sizeof (result), expected, sizeof (expected)); ++ ++ free (winput); ++ } ++ ++ /* For 's' converstion specifier the array is interpreted as a multibyte ++ character sequence and converted to wide characters up to the precision ++ specific value. */ ++ { ++ /* The input size value is to force a heap allocation on temporary ++ buffer (in the old implementation). */ ++ const size_t mbssize = 32 * 1024; ++ char *mbs = xmalloc (mbssize); ++ memset (mbs, 'a', mbssize - 1); ++ mbs[mbssize - 1] = '\0'; ++ ++ const size_t expectedsize = 32 * 1024; ++ wchar_t *expected = xmalloc (expectedsize * sizeof (wchar_t)); ++ wmemset (expected, L'a', expectedsize - 1); ++ expected[expectedsize-1] = L'\0'; ++ ++ const size_t resultsize = mbssize * sizeof (wchar_t); ++ wchar_t *result = xmalloc (resultsize); ++ int ret; ++ ++ ret = swprintf (result, resultsize, L"%.65537s", mbs); ++ TEST_COMPARE (ret, mbssize - 1); ++ TEST_COMPARE_BLOB (result, (ret + 1) * sizeof (wchar_t), ++ expected, expectedsize * sizeof (wchar_t)); ++ ++ ret = swprintf (result, resultsize, L"%1$.65537s", mbs); ++ TEST_COMPARE (ret, mbssize - 1); ++ TEST_COMPARE_BLOB (result, (ret + 1) * sizeof (wchar_t), ++ expected, expectedsize * sizeof (wchar_t)); ++ ++ /* Same test, but with an invalid multibyte sequence. */ ++ mbs[mbssize - 2] = 0xff; ++ ++ ret = swprintf (result, resultsize, L"%.65537s", mbs); ++ TEST_COMPARE (ret, -1); ++ ++ ret = swprintf (result, resultsize, L"%1$.65537s", mbs); ++ TEST_COMPARE (ret, -1); ++ ++ free (mbs); ++ free (result); ++ free (expected); ++ } ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-rh2122501-3.patch b/glibc-rh2122501-3.patch new file mode 100644 index 0000000..331dd92 --- /dev/null +++ b/glibc-rh2122501-3.patch @@ -0,0 +1,356 @@ +commit e1c0c00cc2bdd147bfcf362ada1443bee90465ec +Author: Joseph Myers +Date: Tue Jul 7 14:54:12 2020 +0000 + + Remove most vfprintf width/precision-dependent allocations (bug 14231, bug 26211). + + The vfprintf implementation (used for all printf-family functions) + contains complicated logic to allocate internal buffers of a size + depending on the width and precision used for a format, using either + malloc or alloca depending on that size, and with consequent checks + for size overflow and allocation failure. + + As noted in bug 26211, the version of that logic used when '$' plus + argument number formats are in use is missing the overflow checks, + which can result in segfaults (quite possibly exploitable, I didn't + try to work that out) when the width or precision is in the range + 0x7fffffe0 through 0x7fffffff (maybe smaller values as well in the + wprintf case on 32-bit systems, when the multiplication by sizeof + (CHAR_T) can overflow). + + All that complicated logic in fact appears to be useless. As far as I + can tell, there has been no need (outside the floating-point printf + code, which does its own allocations) for allocations depending on + width or precision since commit + 3e95f6602b226e0de06aaff686dc47b282d7cc16 ("Remove limitation on size + of precision for integers", Sun Sep 12 21:23:32 1999 +0000). Thus, + this patch removes that logic completely, thereby fixing both problems + with excessive allocations for large width and precision for + non-floating-point formats, and the problem with missing overflow + checks with such allocations. Note that this does have the + consequence that width and precision up to INT_MAX are now allowed + where previously INT_MAX / sizeof (CHAR_T) - EXTSIZ or more would have + been rejected, so could potentially expose any other overflows where + the value would previously have been rejected by those removed checks. + + I believe this completely fixes bugs 14231 and 26211. + + Excessive allocations are still possible in the floating-point case + (bug 21127), as are other integer or buffer overflows (see bug 26201). + This does not address the cases where a precision larger than INT_MAX + (embedded in the format string) would be meaningful without printf's + return value overflowing (when it's used with a string format, or %g + without the '#' flag, so the actual output will be much smaller), as + mentioned in bug 17829 comment 8; using size_t internally for + precision to handle that case would be complicated by struct + printf_info being a public ABI. Nor does it address the matter of an + INT_MIN width being negated (bug 17829 comment 7; the same logic + appears a second time in the file as well, in the form of multiplying + by -1). There may be other sources of memory allocations with malloc + in printf functions as well (bug 24988, bug 16060). From inspection, + I think there are also integer overflows in two copies of "if ((width + -= len) < 0)" logic (where width is int, len is size_t and a very long + string could result in spurious padding being output on a 32-bit + system before printf overflows the count of output characters). + + Tested for x86-64 and x86. + + (cherry picked from commit 6caddd34bd7ffb5ac4f36c8e036eee100c2cc535) + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index 51062a7dbf698931..d76b47bd5f932f69 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -64,6 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ + tst-scanf-round \ + tst-renameat2 \ + tst-printf-bz25691 \ ++ tst-vfprintf-width-prec-alloc + + test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble + +diff --git a/stdio-common/bug22.c b/stdio-common/bug22.c +index b26399acb7dfc775..e12b01731e1b4ac8 100644 +--- a/stdio-common/bug22.c ++++ b/stdio-common/bug22.c +@@ -42,7 +42,7 @@ do_test (void) + + ret = fprintf (fp, "%." SN3 "d", 1); + printf ("ret = %d\n", ret); +- if (ret != -1 || errno != EOVERFLOW) ++ if (ret != N3) + return 1; + + ret = fprintf (fp, "%" SN2 "d%" SN2 "d", 1, 1); +diff --git a/stdio-common/tst-vfprintf-width-prec-alloc.c b/stdio-common/tst-vfprintf-width-prec-alloc.c +new file mode 100644 +index 0000000000000000..0a74b53a3389d699 +--- /dev/null ++++ b/stdio-common/tst-vfprintf-width-prec-alloc.c +@@ -0,0 +1,41 @@ ++/* Test large width or precision does not involve large allocation. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++char test_string[] = "test"; ++ ++static int ++do_test (void) ++{ ++ struct rlimit limit; ++ TEST_VERIFY_EXIT (getrlimit (RLIMIT_AS, &limit) == 0); ++ limit.rlim_cur = 200 * 1024 * 1024; ++ TEST_VERIFY_EXIT (setrlimit (RLIMIT_AS, &limit) == 0); ++ FILE *fp = fopen ("/dev/null", "w"); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE (fprintf (fp, "%1000000000d", 1), 1000000000); ++ TEST_COMPARE (fprintf (fp, "%.1000000000s", test_string), 4); ++ TEST_COMPARE (fprintf (fp, "%1000000000d %1000000000d", 1, 2), 2000000001); ++ TEST_COMPARE (fprintf (fp, "%2$.*1$s", 0x7fffffff, test_string), 4); ++ return 0; ++} ++ ++#include +diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c +index dab56b6ba2c7bdbe..6b83ba91a12cdcd5 100644 +--- a/stdio-common/vfprintf.c ++++ b/stdio-common/vfprintf.c +@@ -42,10 +42,6 @@ + + #include + +-/* In some cases we need extra space for all the output which is not +- counted in the width of the string. We assume 32 characters is +- enough. */ +-#define EXTSIZ 32 + #define ARGCHECK(S, Format) \ + do \ + { \ +@@ -1295,7 +1291,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) + + /* Buffer intermediate results. */ + CHAR_T work_buffer[WORK_BUFFER_SIZE]; +- CHAR_T *workstart = NULL; + CHAR_T *workend; + + /* We have to save the original argument pointer. */ +@@ -1404,7 +1399,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) + UCHAR_T pad = L_(' ');/* Padding character. */ + CHAR_T spec; + +- workstart = NULL; + workend = work_buffer + WORK_BUFFER_SIZE; + + /* Get current character in format string. */ +@@ -1496,31 +1490,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) + pad = L_(' '); + left = 1; + } +- +- if (__glibc_unlikely (width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ)) +- { +- __set_errno (EOVERFLOW); +- done = -1; +- goto all_done; +- } +- +- if (width >= WORK_BUFFER_SIZE - EXTSIZ) +- { +- /* We have to use a special buffer. */ +- size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T); +- if (__libc_use_alloca (needed)) +- workend = (CHAR_T *) alloca (needed) + width + EXTSIZ; +- else +- { +- workstart = (CHAR_T *) malloc (needed); +- if (workstart == NULL) +- { +- done = -1; +- goto all_done; +- } +- workend = workstart + width + EXTSIZ; +- } +- } + } + JUMP (*f, step1_jumps); + +@@ -1528,31 +1497,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) + LABEL (width): + width = read_int (&f); + +- if (__glibc_unlikely (width == -1 +- || width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ)) ++ if (__glibc_unlikely (width == -1)) + { + __set_errno (EOVERFLOW); + done = -1; + goto all_done; + } + +- if (width >= WORK_BUFFER_SIZE - EXTSIZ) +- { +- /* We have to use a special buffer. */ +- size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T); +- if (__libc_use_alloca (needed)) +- workend = (CHAR_T *) alloca (needed) + width + EXTSIZ; +- else +- { +- workstart = (CHAR_T *) malloc (needed); +- if (workstart == NULL) +- { +- done = -1; +- goto all_done; +- } +- workend = workstart + width + EXTSIZ; +- } +- } + if (*f == L_('$')) + /* Oh, oh. The argument comes from a positional parameter. */ + goto do_positional; +@@ -1601,34 +1552,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) + } + else + prec = 0; +- if (prec > width && prec > WORK_BUFFER_SIZE - EXTSIZ) +- { +- /* Deallocate any previously allocated buffer because it is +- too small. */ +- if (__glibc_unlikely (workstart != NULL)) +- free (workstart); +- workstart = NULL; +- if (__glibc_unlikely (prec >= INT_MAX / sizeof (CHAR_T) - EXTSIZ)) +- { +- __set_errno (EOVERFLOW); +- done = -1; +- goto all_done; +- } +- size_t needed = ((size_t) prec + EXTSIZ) * sizeof (CHAR_T); +- +- if (__libc_use_alloca (needed)) +- workend = (CHAR_T *) alloca (needed) + prec + EXTSIZ; +- else +- { +- workstart = (CHAR_T *) malloc (needed); +- if (workstart == NULL) +- { +- done = -1; +- goto all_done; +- } +- workend = workstart + prec + EXTSIZ; +- } +- } + JUMP (*f, step2_jumps); + + /* Process 'h' modifier. There might another 'h' following. */ +@@ -1692,10 +1615,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) + /* The format is correctly handled. */ + ++nspecs_done; + +- if (__glibc_unlikely (workstart != NULL)) +- free (workstart); +- workstart = NULL; +- + /* Look for next format specifier. */ + #ifdef COMPILE_WPRINTF + f = __find_specwc ((end_of_spec = ++f)); +@@ -1713,18 +1632,11 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) + + /* Hand off processing for positional parameters. */ + do_positional: +- if (__glibc_unlikely (workstart != NULL)) +- { +- free (workstart); +- workstart = NULL; +- } + done = printf_positional (s, format, readonly_format, ap, &ap_save, + done, nspecs_done, lead_str_end, work_buffer, + save_errno, grouping, thousands_sep); + + all_done: +- if (__glibc_unlikely (workstart != NULL)) +- free (workstart); + /* Unlock the stream. */ + _IO_funlockfile (s); + _IO_cleanup_region_end (0); +@@ -1767,8 +1679,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, + /* Just a counter. */ + size_t cnt; + +- CHAR_T *workstart = NULL; +- + if (grouping == (const char *) -1) + { + #ifdef COMPILE_WPRINTF +@@ -1957,7 +1867,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, + char pad = specs[nspecs_done].info.pad; + CHAR_T spec = specs[nspecs_done].info.spec; + +- workstart = NULL; + CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE; + + /* Fill in last information. */ +@@ -1991,27 +1900,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, + prec = specs[nspecs_done].info.prec; + } + +- /* Maybe the buffer is too small. */ +- if (MAX (prec, width) + EXTSIZ > WORK_BUFFER_SIZE) +- { +- if (__libc_use_alloca ((MAX (prec, width) + EXTSIZ) +- * sizeof (CHAR_T))) +- workend = ((CHAR_T *) alloca ((MAX (prec, width) + EXTSIZ) +- * sizeof (CHAR_T)) +- + (MAX (prec, width) + EXTSIZ)); +- else +- { +- workstart = (CHAR_T *) malloc ((MAX (prec, width) + EXTSIZ) +- * sizeof (CHAR_T)); +- if (workstart == NULL) +- { +- done = -1; +- goto all_done; +- } +- workend = workstart + (MAX (prec, width) + EXTSIZ); +- } +- } +- + /* Process format specifiers. */ + while (1) + { +@@ -2085,18 +1973,12 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, + break; + } + +- if (__glibc_unlikely (workstart != NULL)) +- free (workstart); +- workstart = NULL; +- + /* Write the following constant string. */ + outstring (specs[nspecs_done].end_of_fmt, + specs[nspecs_done].next_fmt + - specs[nspecs_done].end_of_fmt); + } + all_done: +- if (__glibc_unlikely (workstart != NULL)) +- free (workstart); + scratch_buffer_free (&argsbuf); + scratch_buffer_free (&specsbuf); + return done; diff --git a/glibc-rh2122501-4.patch b/glibc-rh2122501-4.patch new file mode 100644 index 0000000..97436f4 --- /dev/null +++ b/glibc-rh2122501-4.patch @@ -0,0 +1,86 @@ +commit 211a30a92b72a18ea4caa35ed503b70bc644923e +Author: Joseph Myers +Date: Mon Nov 8 19:11:51 2021 +0000 + + Fix memmove call in vfprintf-internal.c:group_number + + A recent GCC mainline change introduces errors of the form: + + vfprintf-internal.c: In function 'group_number': + vfprintf-internal.c:2093:15: error: 'memmove' specified bound between 9223372036854775808 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Werror=stringop-overflow=] + 2093 | memmove (w, s, (front_ptr -s) * sizeof (CHAR_T)); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This is a genuine bug in the glibc code: s > front_ptr is always true + at this point in the code, and the intent is clearly for the + subtraction to be the other way round. The other arguments to the + memmove call here also appear to be wrong; w and s point just *after* + the destination and source for copying the rest of the number, so the + size needs to be subtracted to get appropriate pointers for the + copying. Adjust the memmove call to conform to the apparent intent of + the code, so fixing the -Wstringop-overflow error. + + Now, if the original code were ever executed, a buffer overrun would + result. However, I believe this code (introduced in commit + edc1686af0c0fc2eb535f1d38cdf63c1a5a03675, "vfprintf: Reuse work_buffer + in group_number", so in glibc 2.26) is unreachable in prior glibc + releases (so there is no need for a bug in Bugzilla, no need to + consider any backports unless someone wants to build older glibc + releases with GCC 12 and no possibility of this buffer overrun + resulting in a security issue). + + work_buffer is 1000 bytes / 250 wide characters. This case is only + reachable if an initial part of the number, plus a grouped copy of the + rest of the number, fail to fit in that space; that is, if the grouped + number fails to fit in the space. In the wide character case, + grouping is always one wide character, so even with a locale (of which + there aren't any in glibc) grouping every digit, a number would need + to occupy at least 125 wide characters to overflow, and a 64-bit + integer occupies at most 23 characters in octal including a leading 0. + In the narrow character case, the multibyte encoding of the grouping + separator would need to be at least 42 bytes to overflow, again + supposing grouping every digit, but MB_LEN_MAX is 16. So even if we + admit the case of artificially constructed locales not shipped with + glibc, given that such a locale would need to use one of the character + sets supported by glibc, this code cannot be reached at present. (And + POSIX only actually specifies the ' flag for grouping for decimal + output, though glibc acts on it for other bases as well.) + + With binary output (if you consider use of grouping there to be + valid), you'd need a 15-byte multibyte character for overflow; I don't + know if any supported character set has such a character (if, again, + we admit constructed locales using grouping every digit and a grouping + separator chosen to have a multibyte encoding as long as possible, as + well as accepting use of grouping with binary), but given that we have + this code at all (clearly it's not *correct*, or in accordance with + the principle of avoiding arbitrary limits, to skip grouping on + running out of internal space like that), I don't think it should need + any further changes for binary printf support to go in. + + On the other hand, support for large sizes of _BitInt in printf (see + the N2858 proposal) *would* require something to be done about such + arbitrary limits (presumably using dynamic allocation in printf again, + for sufficiently large _BitInt arguments only - currently only + floating-point uses dynamic allocation, and, as previously discussed, + that could actually be replaced by bounded allocation given smarter + code). + + Tested with build-many-glibcs.py for aarch64-linux-gnu (GCC mainline). + Also tested natively for x86_64. + + (cherry picked from commit db6c4935fae6005d46af413b32aa92f4f6059dce) + +diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c +index 6b83ba91a12cdcd5..2d434ba45a67911e 100644 +--- a/stdio-common/vfprintf.c ++++ b/stdio-common/vfprintf.c +@@ -2101,7 +2101,8 @@ group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr, + copy_rest: + /* No further grouping to be done. Copy the rest of the + number. */ +- memmove (w, s, (front_ptr -s) * sizeof (CHAR_T)); ++ w -= s - front_ptr; ++ memmove (w, front_ptr, (s - front_ptr) * sizeof (CHAR_T)); + break; + } + else if (*grouping != '\0') diff --git a/glibc-rh2122501-5.patch b/glibc-rh2122501-5.patch new file mode 100644 index 0000000..f088e5f --- /dev/null +++ b/glibc-rh2122501-5.patch @@ -0,0 +1,81 @@ +commit 8b915921fbf4d32bf68fc3d637413cf96236b3fd +Author: Andreas Schwab +Date: Mon Aug 29 15:05:40 2022 +0200 + + Add test for bug 29530 + + This tests for a bug that was introduced in commit edc1686af0 ("vfprintf: + Reuse work_buffer in group_number") and fixed as a side effect of commit + 6caddd34bd ("Remove most vfprintf width/precision-dependent allocations + (bug 14231, bug 26211)."). + + (cherry picked from commit ca6466e8be32369a658035d69542d47603e58a99) + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index d76b47bd5f932f69..ac61093660ef9063 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -64,7 +64,9 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ + tst-scanf-round \ + tst-renameat2 \ + tst-printf-bz25691 \ +- tst-vfprintf-width-prec-alloc ++ tst-vfprintf-width-prec-alloc \ ++ tst-grouping2 \ ++ # tests + + test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble + +@@ -91,6 +93,7 @@ $(objpfx)bug14.out: $(gen-locales) + $(objpfx)scanf13.out: $(gen-locales) + $(objpfx)test-vfprintf.out: $(gen-locales) + $(objpfx)tst-grouping.out: $(gen-locales) ++$(objpfx)tst-grouping2.out: $(gen-locales) + $(objpfx)tst-sprintf.out: $(gen-locales) + $(objpfx)tst-sscanf.out: $(gen-locales) + $(objpfx)tst-swprintf.out: $(gen-locales) +diff --git a/stdio-common/tst-grouping2.c b/stdio-common/tst-grouping2.c +new file mode 100644 +index 0000000000000000..3024c942a60e51bf +--- /dev/null ++++ b/stdio-common/tst-grouping2.c +@@ -0,0 +1,39 @@ ++/* Test printf with grouping and large width (bug 29530) ++ 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 int ++do_test (void) ++{ ++ const int field_width = 1000; ++ char buf[field_width + 1]; ++ ++ xsetlocale (LC_NUMERIC, "de_DE.UTF-8"); ++ ++ /* This used to crash in group_number. */ ++ TEST_COMPARE (sprintf (buf, "%'*d", field_width, 1000), field_width); ++ TEST_COMPARE_STRING (buf + field_width - 6, " 1.000"); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-rh2125222.patch b/glibc-rh2125222.patch new file mode 100644 index 0000000..7ee14f4 --- /dev/null +++ b/glibc-rh2125222.patch @@ -0,0 +1,54 @@ +commit a23820f6052a740246fdc7dcd9c43ce8eed0c45a +Author: Javier Pello +Date: Mon Sep 5 20:09:01 2022 +0200 + + elf: Fix hwcaps string size overestimation + + Commit dad90d528259b669342757c37dedefa8577e2636 added glibc-hwcaps + support for LD_LIBRARY_PATH and, for this, it adjusted the total + string size required in _dl_important_hwcaps. However, in doing so + it inadvertently altered the calculation of the size required for + the power set strings, as the computation of the power set string + size depended on the first value assigned to the total variable, + which is later shifted, resulting in overallocation of string + space. Fix this now by using a different variable to hold the + string size required for glibc-hwcaps. + + Signed-off-by: Javier Pello + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 2fc4ae67a0f5d051..7ac27fd689187edc 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix + and a "/" suffix once stored in the result. */ + hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1; +- size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) ++ size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) + + hwcaps_counts.total_length); + + /* Count the number of bits set in the masked value. */ +@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + assert (m == cnt); + + /* Determine the total size of all strings together. */ ++ size_t total; + if (cnt == 1) +- total += temp[0].len + 1; ++ total = temp[0].len + 1; + else + { +- total += temp[0].len + temp[cnt - 1].len + 2; ++ total = temp[0].len + temp[cnt - 1].len + 2; + if (cnt > 2) + { + total <<= 1; +@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + /* This is the overall result, including both glibc-hwcaps + subdirectories and the legacy hwcaps subdirectories using the + power set construction. */ ++ total += hwcaps_sz; + struct r_strlenpair *overall_result + = malloc (*sz * sizeof (*result) + total); + if (overall_result == NULL) diff --git a/glibc-rh2139875-1.patch b/glibc-rh2139875-1.patch new file mode 100644 index 0000000..32091ab --- /dev/null +++ b/glibc-rh2139875-1.patch @@ -0,0 +1,32 @@ +commit acb55dcb892d4321ada6fd9b663b28fada432682 +Author: Joseph Myers +Date: Wed Jan 2 18:35:50 2019 +0000 + + Update Linux kernel version in tst-mman-consts.py. + + This patch updates the Linux kernel version in tst-mman-consts.py to + 4.20 (meaning that's the version for which glibc is expected to have + the same constants as the kernel, up to the exceptions listed in the + test). (Once we have more such tests sharing common infrastructure, I + expect the kernel version will be something set in the infrastructure + shared by all such tests, rather than something needing updating + separately for each test for each new kernel version.) + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/tst-mman-consts.py (main): Expect + constants to match with Linux 4.20. + +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index 1a613beec0da16fb..4a2ddd49c4c7282b 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -41,7 +41,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = linux_kernel_version(args.cc) +- linux_version_glibc = (4, 19) ++ linux_version_glibc = (4, 20) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', diff --git a/glibc-rh2139875-2.patch b/glibc-rh2139875-2.patch new file mode 100644 index 0000000..1c3ac5b --- /dev/null +++ b/glibc-rh2139875-2.patch @@ -0,0 +1,31 @@ +commit c7a26cba2ab949216ac9ef245ca78696815ea4c4 +Author: Joseph Myers +Date: Fri Aug 2 11:36:07 2019 +0000 + + Update Linux kernel version number in tst-mman-consts.py to 5.2. + + The tst-mman-consts.py test includes a kernel version number, to avoid + failures because of newly added constants in the kernel (if kernel + headers are newer than this version of glibc) or missing constants in + the kernel (if kernel headers are older than this version of glibc). + This patch updates it to 5.2 to reflect that the MAP_* constants in + glibc are still current as of that kernel version. + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/tst-mman-consts.py (main): Update Linux + kernel version number to 5.2. + +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index 4a2ddd49c4c7282b..9e326b1f31799a72 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -41,7 +41,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = linux_kernel_version(args.cc) +- linux_version_glibc = (4, 20) ++ linux_version_glibc = (5, 2) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', diff --git a/glibc-rh2139875-3.patch b/glibc-rh2139875-3.patch new file mode 100644 index 0000000..6c48115 --- /dev/null +++ b/glibc-rh2139875-3.patch @@ -0,0 +1,61 @@ +commit 71bdf29ac1de04efcce96bc5ce50af3263851ac7 +Author: Joseph Myers +Date: Mon Sep 30 15:49:25 2019 +0000 + + Update bits/mman.h constants and tst-mman-consts.py for Linux 5.3. + + The Linux 5.3 uapi headers have some rearrangement relating to MAP_* + constants, which includes the effect of adding definitions of MAP_SYNC + on powerpc and sparc. This patch updates the corresponding glibc + bits/mman.h headers accordingly, and updates the Linux kernel version + number in tst-mman-consts.py to reflect that these constants are now + current with that kernel version. + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/powerpc/bits/mman.h [__USE_MISC] + (MAP_SYNC): New macro. + * sysdeps/unix/sysv/linux/sparc/bits/mman.h [__USE_MISC] + (MAP_SYNC): Likewise. + * sysdeps/unix/sysv/linux/tst-mman-consts.py (main): Update Linux + kernel version number to 5.3. + +diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/mman.h b/sysdeps/unix/sysv/linux/powerpc/bits/mman.h +index e652467c8c091381..0e7fa647793ed585 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/bits/mman.h ++++ b/sysdeps/unix/sysv/linux/powerpc/bits/mman.h +@@ -36,6 +36,8 @@ + # define MAP_NONBLOCK 0x10000 /* Do not block on IO. */ + # define MAP_STACK 0x20000 /* Allocation is for a stack. */ + # define MAP_HUGETLB 0x40000 /* Create huge page mapping. */ ++# define MAP_SYNC 0x80000 /* Perform synchronous page ++ faults for the mapping. */ + # define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED but do not unmap + underlying mapping. */ + #endif +diff --git a/sysdeps/unix/sysv/linux/sparc/bits/mman.h b/sysdeps/unix/sysv/linux/sparc/bits/mman.h +index 3a3ffb994631e2b6..03f6f732bb5efbe2 100644 +--- a/sysdeps/unix/sysv/linux/sparc/bits/mman.h ++++ b/sysdeps/unix/sysv/linux/sparc/bits/mman.h +@@ -36,6 +36,8 @@ + # define MAP_NONBLOCK 0x10000 /* Do not block on IO. */ + # define MAP_STACK 0x20000 /* Allocation is for a stack. */ + # define MAP_HUGETLB 0x40000 /* Create huge page mapping. */ ++# define MAP_SYNC 0x80000 /* Perform synchronous page ++ faults for the mapping. */ + # define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED but do not unmap + underlying mapping. */ + #endif +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index 9e326b1f31799a72..42914e4e0ba84712 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -41,7 +41,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = linux_kernel_version(args.cc) +- linux_version_glibc = (5, 2) ++ linux_version_glibc = (5, 3) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', diff --git a/glibc-rh2141989.patch b/glibc-rh2141989.patch new file mode 100644 index 0000000..70ab8e4 --- /dev/null +++ b/glibc-rh2141989.patch @@ -0,0 +1,101 @@ +This change is equivalent to this upstream change: + +commit 22a46dee24351fd5f4f188ad80554cad79c82524 +Author: Florian Weimer +Date: Tue Nov 8 14:15:02 2022 +0100 + + Linux: Support __IPC_64 in sysvctl *ctl command arguments (bug 29771) + + Old applications pass __IPC_64 as part of the command argument because + old glibc did not check for unknown commands, and passed through the + arguments directly to the kernel, without adding __IPC_64. + Applications need to continue doing that for old glibc compatibility, + so this commit enables this approach in current glibc. + + For msgctl and shmctl, if no translation is required, make + direct system calls, as we did before the time64 changes. If + translation is required, mask __IPC_64 from the command argument. + + For semctl, the union-in-vararg argument handling means that + translation is needed on all architectures. + + Reviewed-by: Adhemerval Zanella + +The downstream versions of shmctl and msgctl did not produce +errors because they lacked a -1 error return path. There is no +translation requirement downstream on any architecture, so we +can remove the switch from shmctl and msgctl. + +For semctl, we have to do the varargs translation, so this patch adds +the same masking as the upstream commit. + +diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c +index 3362f4562f58f28b..7280cba31a8815a2 100644 +--- a/sysdeps/unix/sysv/linux/msgctl.c ++++ b/sysdeps/unix/sysv/linux/msgctl.c +@@ -29,20 +29,6 @@ + int + __new_msgctl (int msqid, int cmd, struct msqid_ds *buf) + { +- switch (cmd) +- { +- case IPC_RMID: +- case IPC_SET: +- case IPC_STAT: +- case MSG_STAT: +- case MSG_STAT_ANY: +- case IPC_INFO: +- case MSG_INFO: +- break; +- default: +- __set_errno (EINVAL); +- return -1; +- } + #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS + return INLINE_SYSCALL_CALL (msgctl, msqid, cmd | __IPC_64, buf); + #else +diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c +index 03c56c69a5412c82..16d3f04fadd039ab 100644 +--- a/sysdeps/unix/sysv/linux/semctl.c ++++ b/sysdeps/unix/sysv/linux/semctl.c +@@ -42,6 +42,13 @@ __new_semctl (int semid, int semnum, int cmd, ...) + union semun arg = { 0 }; + va_list ap; + ++ /* Some applications pass the __IPC_64 flag in cmd, to invoke ++ previously unsupported commands back when there was no EINVAL ++ error checking in glibc. Mask the flag for the switch statements ++ below. msgctl_syscall adds back the __IPC_64 flag for the actual ++ system call. */ ++ cmd &= ~__IPC_64; ++ + /* Get the argument only if required. */ + switch (cmd) + { +diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c +index 00768bc47614f9aa..25c5152944a6fcf3 100644 +--- a/sysdeps/unix/sysv/linux/shmctl.c ++++ b/sysdeps/unix/sysv/linux/shmctl.c +@@ -33,22 +33,6 @@ + int + __new_shmctl (int shmid, int cmd, struct shmid_ds *buf) + { +- switch (cmd) +- { +- case IPC_RMID: +- case SHM_LOCK: +- case SHM_UNLOCK: +- case IPC_SET: +- case IPC_STAT: +- case SHM_STAT: +- case SHM_STAT_ANY: +- case IPC_INFO: +- case SHM_INFO: +- break; +- default: +- __set_errno (EINVAL); +- break; +- } + #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS + return INLINE_SYSCALL_CALL (shmctl, shmid, cmd | __IPC_64, buf); + #else diff --git a/glibc-rh2142937-1.patch b/glibc-rh2142937-1.patch new file mode 100644 index 0000000..c9279a7 --- /dev/null +++ b/glibc-rh2142937-1.patch @@ -0,0 +1,354 @@ +commit 2fe64148a81f0d78050c302f34a6853d21f7cae4 +Author: DJ Delorie +Date: Mon Mar 28 23:53:33 2022 -0400 + + Allow for unpriviledged nested containers + + If the build itself is run in a container, we may not be able to + fully set up a nested container for test-container testing. + Notably is the mounting of /proc, since it's critical that it + be mounted from within the same PID namespace as its users, and + thus cannot be bind mounted from outside the container like other + mounts. + + This patch defaults to using the parent's PID namespace instead of + creating a new one, as this is more likely to be allowed. + + If the test needs an isolated PID namespace, it should add the "pidns" + command to its init script. + + Reviewed-by: Carlos O'Donell + +Conflicts: + nss/tst-reload2.c + (not in RHEL-8) + support/Makefile + (RHEL-8 missing some routines in libsupport-routines) + +diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c +index f381cb0fa7e6b93d..45ac033a0f897088 100644 +--- a/elf/tst-pldd.c ++++ b/elf/tst-pldd.c +@@ -85,6 +85,8 @@ in_str_list (const char *libname, const char *const strlist[]) + static int + do_test (void) + { ++ support_need_proc ("needs /proc/sys/kernel/yama/ptrace_scope and /proc/$child"); ++ + /* Check if our subprocess can be debugged with ptrace. */ + { + int ptrace_scope = support_ptrace_scope (); +diff --git a/nptl/tst-pthread-getattr.c b/nptl/tst-pthread-getattr.c +index 273b6073abe9cb60..f1c0b39f3a27724c 100644 +--- a/nptl/tst-pthread-getattr.c ++++ b/nptl/tst-pthread-getattr.c +@@ -28,6 +28,8 @@ + #include + #include + ++#include ++ + /* There is an obscure bug in the kernel due to which RLIMIT_STACK is sometimes + returned as unlimited when it is not, which may cause this test to fail. + There is also the other case where RLIMIT_STACK is intentionally set as +@@ -152,6 +154,8 @@ check_stack_top (void) + static int + do_test (void) + { ++ support_need_proc ("Reads /proc/self/maps to get stack size."); ++ + pagesize = sysconf (_SC_PAGESIZE); + return check_stack_top (); + } +diff --git a/support/Makefile b/support/Makefile +index 636d69c4f8e7e139..e184fccbe7d2310c 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -59,6 +59,7 @@ libsupport-routines = \ + support_format_hostent \ + support_format_netent \ + support_isolate_in_subprocess \ ++ support_need_proc \ + support_process_state \ + support_ptrace \ + support_openpty \ +diff --git a/support/support.h b/support/support.h +index 96833bd4e992e6d3..1466eb29f840fa59 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -81,6 +81,11 @@ char *support_quote_string (const char *); + regular file open for writing, and initially empty. */ + int support_descriptor_supports_holes (int fd); + ++/* Predicates that a test requires a working /proc filesystem. This ++ call will exit with UNSUPPORTED if /proc is not available, printing ++ WHY_MSG as part of the diagnostic. */ ++void support_need_proc (const char *why_msg); ++ + /* Error-checking wrapper functions which terminate the process on + error. */ + +diff --git a/support/support_need_proc.c b/support/support_need_proc.c +new file mode 100644 +index 0000000000000000..9b4eab7539b2d6c3 +--- /dev/null ++++ b/support/support_need_proc.c +@@ -0,0 +1,35 @@ ++/* Indicate that a test requires a working /proc. ++ 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 ++ ++/* We test for /proc/self/maps since that's one of the files that one ++ of our tests actually uses, but the general idea is if Linux's ++ /proc/ (procfs) filesystem is mounted. If not, the process exits ++ with an UNSUPPORTED result code. */ ++ ++void ++support_need_proc (const char *why_msg) ++{ ++#ifdef __linux__ ++ if (access ("/proc/self/maps", R_OK)) ++ FAIL_UNSUPPORTED ("/proc is not available, %s", why_msg); ++#endif ++} +diff --git a/support/test-container.c b/support/test-container.c +index 9975c8cb7bc9a955..2bce4db841ff7668 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -95,6 +95,7 @@ int verbose = 0; + * mytest.root/mytest.script has a list of "commands" to run: + syntax: + # comment ++ pidns + su + mv FILE FILE + cp FILE FILE +@@ -120,6 +121,8 @@ int verbose = 0; + + details: + - '#': A comment. ++ - 'pidns': Require a separate PID namespace, prints comment if it can't ++ (default is a shared pid namespace) + - 'su': Enables running test as root in the container. + - 'mv': A minimal move files command. + - 'cp': A minimal copy files command. +@@ -143,7 +146,7 @@ int verbose = 0; + * Simple, easy to review code (i.e. prefer simple naive code over + complex efficient code) + +- * The current implementation ist parallel-make-safe, but only in ++ * The current implementation is parallel-make-safe, but only in + that it uses a lock to prevent parallel access to the testroot. */ + + +@@ -222,11 +225,37 @@ concat (const char *str, ...) + return bufs[n]; + } + ++/* Like the above, but put spaces between words. Caller frees. */ ++static char * ++concat_words (char **words, int num_words) ++{ ++ int len = 0; ++ int i; ++ char *rv, *p; ++ ++ for (i = 0; i < num_words; i ++) ++ { ++ len += strlen (words[i]); ++ len ++; ++ } ++ ++ p = rv = (char *) xmalloc (len); ++ ++ for (i = 0; i < num_words; i ++) ++ { ++ if (i > 0) ++ p = stpcpy (p, " "); ++ p = stpcpy (p, words[i]); ++ } ++ ++ return rv; ++} ++ + /* Try to mount SRC onto DEST. */ + static void + trymount (const char *src, const char *dest) + { +- if (mount (src, dest, "", MS_BIND, NULL) < 0) ++ if (mount (src, dest, "", MS_BIND | MS_REC, NULL) < 0) + FAIL_EXIT1 ("can't mount %s onto %s\n", src, dest); + } + +@@ -709,6 +738,9 @@ main (int argc, char **argv) + gid_t original_gid; + /* If set, the test runs as root instead of the user running the testsuite. */ + int be_su = 0; ++ int require_pidns = 0; ++ const char *pidns_comment = NULL; ++ int do_proc_mounts = 0; + int UMAP; + int GMAP; + /* Used for "%lld %lld 1" so need not be large. */ +@@ -991,6 +1023,12 @@ main (int argc, char **argv) + { + be_su = 1; + } ++ else if (nt >= 1 && strcmp (the_words[0], "pidns") == 0) ++ { ++ require_pidns = 1; ++ if (nt > 1) ++ pidns_comment = concat_words (the_words + 1, nt - 1); ++ } + else if (nt == 3 && strcmp (the_words[0], "mkdirp") == 0) + { + long int m; +@@ -1048,7 +1086,8 @@ main (int argc, char **argv) + + #ifdef CLONE_NEWNS + /* The unshare here gives us our own spaces and capabilities. */ +- if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0) ++ if (unshare (CLONE_NEWUSER | CLONE_NEWNS ++ | (require_pidns ? CLONE_NEWPID : 0)) < 0) + { + /* Older kernels may not support all the options, or security + policy may block this call. */ +@@ -1059,6 +1098,11 @@ main (int argc, char **argv) + check_for_unshare_hints (); + FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno)); + } ++ /* We're about to exit anyway, it's "safe" to call unshare again ++ just to see if the CLONE_NEWPID caused the error. */ ++ else if (require_pidns && unshare (CLONE_NEWUSER | CLONE_NEWNS) >= 0) ++ FAIL_EXIT1 ("unable to unshare pid ns: %s : %s", strerror (errno), ++ pidns_comment ? pidns_comment : "required by test"); + else + FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno)); + } +@@ -1074,6 +1118,15 @@ main (int argc, char **argv) + trymount (support_srcdir_root, new_srcdir_path); + trymount (support_objdir_root, new_objdir_path); + ++ /* It may not be possible to mount /proc directly. */ ++ if (! require_pidns) ++ { ++ char *new_proc = concat (new_root_path, "/proc", NULL); ++ xmkdirp (new_proc, 0755); ++ trymount ("/proc", new_proc); ++ do_proc_mounts = 1; ++ } ++ + xmkdirp (concat (new_root_path, "/dev", NULL), 0755); + devmount (new_root_path, "null"); + devmount (new_root_path, "zero"); +@@ -1136,42 +1189,60 @@ main (int argc, char **argv) + + maybe_xmkdir ("/tmp", 0755); + +- /* Now that we're pid 1 (effectively "root") we can mount /proc */ +- maybe_xmkdir ("/proc", 0777); +- if (mount ("proc", "/proc", "proc", 0, NULL) < 0) +- FAIL_EXIT1 ("Unable to mount /proc: "); +- +- /* We map our original UID to the same UID in the container so we +- can own our own files normally. */ +- UMAP = open ("/proc/self/uid_map", O_WRONLY); +- if (UMAP < 0) +- FAIL_EXIT1 ("can't write to /proc/self/uid_map\n"); +- +- sprintf (tmp, "%lld %lld 1\n", +- (long long) (be_su ? 0 : original_uid), (long long) original_uid); +- write (UMAP, tmp, strlen (tmp)); +- xclose (UMAP); +- +- /* We must disable setgroups () before we can map our groups, else we +- get EPERM. */ +- GMAP = open ("/proc/self/setgroups", O_WRONLY); +- if (GMAP >= 0) ++ if (require_pidns) + { +- /* We support kernels old enough to not have this. */ +- write (GMAP, "deny\n", 5); +- xclose (GMAP); ++ /* Now that we're pid 1 (effectively "root") we can mount /proc */ ++ maybe_xmkdir ("/proc", 0777); ++ if (mount ("proc", "/proc", "proc", 0, NULL) != 0) ++ { ++ /* This happens if we're trying to create a nested container, ++ like if the build is running under podman, and we lack ++ priviledges. ++ ++ Ideally we would WARN here, but that would just add noise to ++ *every* test-container test, and the ones that care should ++ have their own relevent diagnostics. ++ ++ FAIL_EXIT1 ("Unable to mount /proc: "); */ ++ } ++ else ++ do_proc_mounts = 1; + } + +- /* We map our original GID to the same GID in the container so we +- can own our own files normally. */ +- GMAP = open ("/proc/self/gid_map", O_WRONLY); +- if (GMAP < 0) +- FAIL_EXIT1 ("can't write to /proc/self/gid_map\n"); ++ if (do_proc_mounts) ++ { ++ /* We map our original UID to the same UID in the container so we ++ can own our own files normally. */ ++ UMAP = open ("/proc/self/uid_map", O_WRONLY); ++ if (UMAP < 0) ++ FAIL_EXIT1 ("can't write to /proc/self/uid_map\n"); ++ ++ sprintf (tmp, "%lld %lld 1\n", ++ (long long) (be_su ? 0 : original_uid), (long long) original_uid); ++ write (UMAP, tmp, strlen (tmp)); ++ xclose (UMAP); ++ ++ /* We must disable setgroups () before we can map our groups, else we ++ get EPERM. */ ++ GMAP = open ("/proc/self/setgroups", O_WRONLY); ++ if (GMAP >= 0) ++ { ++ /* We support kernels old enough to not have this. */ ++ write (GMAP, "deny\n", 5); ++ xclose (GMAP); ++ } + +- sprintf (tmp, "%lld %lld 1\n", +- (long long) (be_su ? 0 : original_gid), (long long) original_gid); +- write (GMAP, tmp, strlen (tmp)); +- xclose (GMAP); ++ /* We map our original GID to the same GID in the container so we ++ can own our own files normally. */ ++ GMAP = open ("/proc/self/gid_map", O_WRONLY); ++ if (GMAP < 0) ++ FAIL_EXIT1 ("can't write to /proc/self/gid_map\n"); ++ ++ sprintf (tmp, "%lld %lld 1\n", ++ (long long) (be_su ? 0 : original_gid), (long long) original_gid); ++ write (GMAP, tmp, strlen (tmp)); ++ xclose (GMAP); ++ } + + if (change_cwd) + { diff --git a/glibc-rh2142937-2.patch b/glibc-rh2142937-2.patch new file mode 100644 index 0000000..e9102b6 --- /dev/null +++ b/glibc-rh2142937-2.patch @@ -0,0 +1,24 @@ +commit b2cd93fce666fdc8c9a5c64af2741a8a6940ac99 +Author: Adhemerval Zanella +Date: Fri Mar 25 11:16:49 2022 -0300 + + elf: Fix wrong fscanf usage on tst-pldd + + To take in consideration the extra '\0'. + + Checked on x86_64-linux-gnu. + +diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c +index 45ac033a0f897088..ab89798e250fdccc 100644 +--- a/elf/tst-pldd.c ++++ b/elf/tst-pldd.c +@@ -115,7 +115,8 @@ do_test (void) + TEST_VERIFY (out != NULL); + + /* First line is in the form of : */ +- TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2); ++ TEST_COMPARE (fscanf (out, "%u: " STRINPUT (sizeof (buffer) - 1), &pid, ++ buffer), 2); + + TEST_COMPARE (pid, *target_pid_ptr); + TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0); diff --git a/glibc-rh2142937-3.patch b/glibc-rh2142937-3.patch new file mode 100644 index 0000000..a61dfde --- /dev/null +++ b/glibc-rh2142937-3.patch @@ -0,0 +1,37 @@ +commit c353689e49e72f3aafa1a9e68d4f7a4f33a79cbe +Author: Adhemerval Zanella +Date: Tue Jul 5 12:58:40 2022 -0300 + + elf: Fix wrong fscanf usage on tst-pldd + + The fix done b2cd93fce666fdc8c9a5c64af2741a8a6940ac99 does not really + work since macro strification does not expand the sizeof nor the + arithmetic operation. + + Checked on x86_64-linux-gnu. + +diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c +index ab89798e250fdccc..52c0a75be5a808d1 100644 +--- a/elf/tst-pldd.c ++++ b/elf/tst-pldd.c +@@ -108,15 +108,16 @@ do_test (void) + loader and libc. */ + { + pid_t pid; +- char buffer[512]; +-#define STRINPUT(size) "%" # size "s" ++#define BUFFERLEN 511 ++ char buffer[BUFFERLEN + 1]; ++#define STRINPUT(size) XSTRINPUT(size) ++#define XSTRINPUT(size) "%" # size "s" + + FILE *out = fmemopen (pldd.out.buffer, pldd.out.length, "r"); + TEST_VERIFY (out != NULL); + + /* First line is in the form of : */ +- TEST_COMPARE (fscanf (out, "%u: " STRINPUT (sizeof (buffer) - 1), &pid, +- buffer), 2); ++ TEST_COMPARE (fscanf (out, "%u: " STRINPUT (BUFFERLEN), &pid, buffer), 2); + + TEST_COMPARE (pid, *target_pid_ptr); + TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0); diff --git a/glibc-rh2144568.patch b/glibc-rh2144568.patch new file mode 100644 index 0000000..82f86ad --- /dev/null +++ b/glibc-rh2144568.patch @@ -0,0 +1,45 @@ +commit eb4181e9f4a512de37dad4ba623c921671584dea +Author: Vladislav Khmelevsky +Date: Thu Nov 17 12:47:29 2022 +0400 + + elf: Fix rtld-audit trampoline for aarch64 + + This patch fixes two problems with audit: + + 1. The DL_OFFSET_RV_VPCS offset was mixed up with DL_OFFSET_RG_VPCS, + resulting in x2 register value nulling in RG structure. + + 2. We need to preserve the x8 register before function call, but + don't have to save it's new value and restore it before return. + + Anyway the final restore was using OFFSET_RV instead of OFFSET_RG value + which is wrong (althoug doesn't affect anything). + + Reviewed-by: Adhemerval Zanella + +diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S +index a83e7fc5f97047e2..b4b9c86224785a2c 100644 +--- a/sysdeps/aarch64/dl-trampoline.S ++++ b/sysdeps/aarch64/dl-trampoline.S +@@ -282,12 +282,11 @@ _dl_runtime_profile: + stp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] + stp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] + stp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] +- str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] + stp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] + stp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] + stp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] + stp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] +- str xzr, [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS] ++ str xzr, [X29, #OFFSET_RV + DL_OFFSET_RV_VPCS] + + /* Setup call to pltexit */ + ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0] +@@ -299,7 +298,6 @@ _dl_runtime_profile: + ldp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] + ldp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] + ldp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] +- ldr x8, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4] + ldp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] + ldp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] + ldp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] diff --git a/glibc-rh2154914-1.patch b/glibc-rh2154914-1.patch new file mode 100644 index 0000000..3eafe16 --- /dev/null +++ b/glibc-rh2154914-1.patch @@ -0,0 +1,297 @@ +Maintain an explicit order of tunables, so that the tunable_list +array and the tunable_id_t constant can remain consistent over time. + +Related to this upstream bug: + + Internal tunables ABI depends on awk array iteration order + + +The new dl-tunables.list files are already on the sysdeps search +path, which is why the existing Makeconfig rule picks them up. +The files for RHEL 8.7.z were created by applying the gen-tunables.awk +part of this patch to RHEL 8.7.0 (glibc-2.28-211.el8_7, to be precise). +The sysdeps/unix/sysv/linux/**/dl-tunables.list files were created +based on the generated error message during the RHEL 8.7.z build. +Afterwards, the glibc.rtld.dynamic_sort tunable was added at the +end of the files, for the RHEL 8.8.0 build. + +Going forward, new tunables will have to be added manually to the end +of those files. Existing tunables should not be deleted. For +deletion, the script would have to be extended to be able to create +gaps in the tunable_list array. + +diff --git a/scripts/gen-tunables.awk b/scripts/gen-tunables.awk +index 622199061a140ccd..8ebfb560976ead41 100644 +--- a/scripts/gen-tunables.awk ++++ b/scripts/gen-tunables.awk +@@ -12,6 +12,7 @@ BEGIN { + tunable="" + ns="" + top_ns="" ++ tunable_order_count = 0 + } + + # Skip over blank lines and comments. +@@ -78,6 +79,37 @@ $1 == "}" { + next + } + ++$1 == "@order" { ++ if (top_ns != "") { ++ printf("%s:%d: error: invalid @order directive inside namespace %s\n", ++ FILENAME, FNR, top_ns) > "/dev/stderr" ++ exit 1 ++ } ++ if (NF != 2) { ++ printf("%s:%d: error: invalid argument count in @order directive\n", ++ FILENAME, FNR) > "/dev/stderr" ++ exit 1 ++ } ++ order_arg = $2 ++ if (split(order_arg, indices, /\./) != 3) { ++ printf("%s:%d: error: invalid tunable syntax in @order directive\n", ++ FILENAME, FNR) > "/dev/stderr" ++ exit 1 ++ } ++ t = indices[1] ++ n = indices[2] ++ m = indices[3] ++ if ((t, n, m) in tunable_order) { ++ printf("%s:%d: error: duplicate\"@order %s\"\n" \ ++ FILENAME, FNR, order_arg) > "/dev/stderr" ++ exit 1 ++ } ++ ++tunable_order_count ++ tunable_order[t,n,m] = tunable_order_count ++ tunable_order_list[tunable_order_count] = t SUBSEP n SUBSEP m ++ next ++} ++ + # Everything else, which could either be a tunable without any attributes or a + # tunable attribute. + { +@@ -137,6 +169,31 @@ END { + exit 1 + } + ++ missing_order = 0 ++ for (tnm in types) { ++ if (!(tnm in tunable_order)) { ++ if (!missing_order) { ++ print "error: Missing @order directives:" > "/dev/stderr" ++ missing_order = 1 ++ } ++ split(tnm, indices, SUBSEP) ++ printf("@order %s.%s.%s\n", indices[1], indices[2], indices[3]) \ ++ > "/dev/stderr" ++ } ++ } ++ for (i = 1; i <= tunable_order_count; ++i) { ++ tnm = tunable_order_list[i] ++ if (!(tnm in types)) { ++ split(tnm, indices, SUBSEP) ++ printf("error: tunable in \"@order %s.%s.%s\" not known\n", \ ++ indices[1], indices[2], indices[3]) > "/dev/stderr" ++ missing_order = 1 ++ } ++ } ++ if (missing_order) { ++ exit 1 ++ } ++ + print "/* AUTOGENERATED by gen-tunables.awk. */" + print "#ifndef _TUNABLES_H_" + print "# error \"Do not include this file directly.\"" +@@ -147,7 +204,8 @@ END { + # Now, the enum names + print "\ntypedef enum" + print "{" +- for (tnm in types) { ++ for (i = 1; i <= tunable_order_count; ++i) { ++ tnm = tunable_order_list[i] + split (tnm, indices, SUBSEP); + t = indices[1]; + n = indices[2]; +@@ -159,7 +217,8 @@ END { + # Finally, the tunable list. + print "\n#ifdef TUNABLES_INTERNAL" + print "static tunable_t tunable_list[] attribute_relro = {" +- for (tnm in types) { ++ for (i = 1; i <= tunable_order_count; ++i) { ++ tnm = tunable_order_list[i] + split (tnm, indices, SUBSEP); + t = indices[1]; + n = indices[2]; +diff --git a/sysdeps/unix/sysv/linux/aarch64/dl-tunables.list b/sysdeps/unix/sysv/linux/aarch64/dl-tunables.list +new file mode 100644 +index 0000000000000000..5c3c5292025607a1 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/aarch64/dl-tunables.list +@@ -0,0 +1,26 @@ ++# Order of tunables in RHEL 8.7.0. ++@order glibc.rtld.nns ++@order glibc.elision.skip_lock_after_retries ++@order glibc.malloc.trim_threshold ++@order glibc.malloc.perturb ++@order glibc.cpu.name ++@order glibc.elision.tries ++@order glibc.elision.enable ++@order glibc.malloc.mxfast ++@order glibc.elision.skip_lock_busy ++@order glibc.malloc.top_pad ++@order glibc.cpu.hwcap_mask ++@order glibc.malloc.mmap_max ++@order glibc.elision.skip_trylock_internal_abort ++@order glibc.malloc.tcache_unsorted_limit ++@order glibc.elision.skip_lock_internal_abort ++@order glibc.malloc.arena_max ++@order glibc.malloc.mmap_threshold ++@order glibc.malloc.tcache_count ++@order glibc.malloc.arena_test ++@order glibc.rtld.optional_static_tls ++@order glibc.malloc.tcache_max ++@order glibc.malloc.check ++ ++# Tunables added in RHEL 8.8.0 ++@order glibc.rtld.dynamic_sort +diff --git a/sysdeps/unix/sysv/linux/i386/dl-tunables.list b/sysdeps/unix/sysv/linux/i386/dl-tunables.list +new file mode 100644 +index 0000000000000000..b9cad4af62d9f2e5 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/i386/dl-tunables.list +@@ -0,0 +1,33 @@ ++# Order of tunables in RHEL 8.7.0. ++@order glibc.rtld.nns ++@order glibc.elision.skip_lock_after_retries ++@order glibc.malloc.trim_threshold ++@order glibc.malloc.perturb ++@order glibc.cpu.x86_shared_cache_size ++@order glibc.elision.tries ++@order glibc.elision.enable ++@order glibc.cpu.x86_rep_movsb_threshold ++@order glibc.malloc.mxfast ++@order glibc.elision.skip_lock_busy ++@order glibc.malloc.top_pad ++@order glibc.cpu.x86_rep_stosb_threshold ++@order glibc.cpu.x86_non_temporal_threshold ++@order glibc.cpu.x86_shstk ++@order glibc.cpu.hwcap_mask ++@order glibc.malloc.mmap_max ++@order glibc.elision.skip_trylock_internal_abort ++@order glibc.malloc.tcache_unsorted_limit ++@order glibc.cpu.x86_ibt ++@order glibc.cpu.hwcaps ++@order glibc.elision.skip_lock_internal_abort ++@order glibc.malloc.arena_max ++@order glibc.malloc.mmap_threshold ++@order glibc.cpu.x86_data_cache_size ++@order glibc.malloc.tcache_count ++@order glibc.malloc.arena_test ++@order glibc.rtld.optional_static_tls ++@order glibc.malloc.tcache_max ++@order glibc.malloc.check ++ ++# Tunables added in RHEL 8.8.0 ++@order glibc.rtld.dynamic_sort +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list +new file mode 100644 +index 0000000000000000..ee1e6fca95e1f2da +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list +@@ -0,0 +1,26 @@ ++# Order of tunables in RHEL 8.7.0. ++@order glibc.rtld.nns ++@order glibc.elision.skip_lock_after_retries ++@order glibc.malloc.trim_threshold ++@order glibc.malloc.perturb ++@order glibc.elision.tries ++@order glibc.elision.enable ++@order glibc.malloc.mxfast ++@order glibc.elision.skip_lock_busy ++@order glibc.malloc.top_pad ++@order glibc.cpu.hwcap_mask ++@order glibc.malloc.mmap_max ++@order glibc.elision.skip_trylock_internal_abort ++@order glibc.malloc.tcache_unsorted_limit ++@order glibc.elision.skip_lock_internal_abort ++@order glibc.malloc.arena_max ++@order glibc.malloc.mmap_threshold ++@order glibc.cpu.cached_memopt ++@order glibc.malloc.tcache_count ++@order glibc.malloc.arena_test ++@order glibc.rtld.optional_static_tls ++@order glibc.malloc.tcache_max ++@order glibc.malloc.check ++ ++# Tunables added in RHEL 8.8.0 ++@order glibc.rtld.dynamic_sort +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/dl-tunables.list b/sysdeps/unix/sysv/linux/s390/s390-64/dl-tunables.list +new file mode 100644 +index 0000000000000000..099e28d8f8e67944 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/dl-tunables.list +@@ -0,0 +1,25 @@ ++# Order of tunables in RHEL 8.7.0. ++@order glibc.rtld.nns ++@order glibc.elision.skip_lock_after_retries ++@order glibc.malloc.trim_threshold ++@order glibc.malloc.perturb ++@order glibc.elision.tries ++@order glibc.elision.enable ++@order glibc.malloc.mxfast ++@order glibc.elision.skip_lock_busy ++@order glibc.malloc.top_pad ++@order glibc.cpu.hwcap_mask ++@order glibc.malloc.mmap_max ++@order glibc.elision.skip_trylock_internal_abort ++@order glibc.malloc.tcache_unsorted_limit ++@order glibc.elision.skip_lock_internal_abort ++@order glibc.malloc.arena_max ++@order glibc.malloc.mmap_threshold ++@order glibc.malloc.tcache_count ++@order glibc.malloc.arena_test ++@order glibc.rtld.optional_static_tls ++@order glibc.malloc.tcache_max ++@order glibc.malloc.check ++ ++# Tunables added in RHEL 8.8.0 ++@order glibc.rtld.dynamic_sort +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list +new file mode 100644 +index 0000000000000000..b9cad4af62d9f2e5 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list +@@ -0,0 +1,33 @@ ++# Order of tunables in RHEL 8.7.0. ++@order glibc.rtld.nns ++@order glibc.elision.skip_lock_after_retries ++@order glibc.malloc.trim_threshold ++@order glibc.malloc.perturb ++@order glibc.cpu.x86_shared_cache_size ++@order glibc.elision.tries ++@order glibc.elision.enable ++@order glibc.cpu.x86_rep_movsb_threshold ++@order glibc.malloc.mxfast ++@order glibc.elision.skip_lock_busy ++@order glibc.malloc.top_pad ++@order glibc.cpu.x86_rep_stosb_threshold ++@order glibc.cpu.x86_non_temporal_threshold ++@order glibc.cpu.x86_shstk ++@order glibc.cpu.hwcap_mask ++@order glibc.malloc.mmap_max ++@order glibc.elision.skip_trylock_internal_abort ++@order glibc.malloc.tcache_unsorted_limit ++@order glibc.cpu.x86_ibt ++@order glibc.cpu.hwcaps ++@order glibc.elision.skip_lock_internal_abort ++@order glibc.malloc.arena_max ++@order glibc.malloc.mmap_threshold ++@order glibc.cpu.x86_data_cache_size ++@order glibc.malloc.tcache_count ++@order glibc.malloc.arena_test ++@order glibc.rtld.optional_static_tls ++@order glibc.malloc.tcache_max ++@order glibc.malloc.check ++ ++# Tunables added in RHEL 8.8.0 ++@order glibc.rtld.dynamic_sort diff --git a/glibc-rh2154914-2.patch b/glibc-rh2154914-2.patch new file mode 100644 index 0000000..4c89744 --- /dev/null +++ b/glibc-rh2154914-2.patch @@ -0,0 +1,81 @@ +Move _dl_dso_sort_algo out of _rtld_global_ro. It is only used +locally in elf/dl-sort-maps.c. This avoids changing the internal +_rtld_global_ro ABI. + +diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c +index 6f5c17b47b98fbc7..aeb79b40b45054c0 100644 +--- a/elf/dl-sort-maps.c ++++ b/elf/dl-sort-maps.c +@@ -290,12 +290,21 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, + } + } + ++/* DSO sort algorithm to use. */ ++enum dso_sort_algorithm ++ { ++ dso_sort_algorithm_original, ++ dso_sort_algorithm_dfs ++ }; ++ ++static enum dso_sort_algorithm _dl_dso_sort_algo; ++ + void + _dl_sort_maps_init (void) + { + int32_t algorithm = TUNABLE_GET (glibc, rtld, dynamic_sort, int32_t, NULL); +- GLRO(dl_dso_sort_algo) = algorithm == 1 ? dso_sort_algorithm_original +- : dso_sort_algorithm_dfs; ++ _dl_dso_sort_algo = (algorithm == 1 ? dso_sort_algorithm_original ++ : dso_sort_algorithm_dfs); + } + + void +@@ -309,7 +318,7 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, + PTR_MANGLE/DEMANGLE, further impairing performance of small, common + input cases. A simple if-case with direct function calls appears to + be the fastest. */ +- if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original)) ++ if (__glibc_likely (_dl_dso_sort_algo == dso_sort_algorithm_original)) + _dl_sort_maps_original (maps, nmaps, force_first, for_fini); + else + _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini); +diff --git a/elf/dl-support.c b/elf/dl-support.c +index ae03aec9764e29d3..e9943e889ef447ad 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -155,8 +155,6 @@ size_t _dl_phnum; + uint64_t _dl_hwcap __attribute__ ((nocommon)); + uint64_t _dl_hwcap2 __attribute__ ((nocommon)); + +-enum dso_sort_algorithm _dl_dso_sort_algo; +- + /* The value of the FPU control word the kernel will preset in hardware. */ + fpu_control_t _dl_fpu_control = _FPU_DEFAULT; + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 2c1b4c47c6a6c643..29bbde3e83e37d7e 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -240,13 +240,6 @@ enum allowmask + }; + + +-/* DSO sort algorithm to use (check dl-sort-maps.c). */ +-enum dso_sort_algorithm +- { +- dso_sort_algorithm_original, +- dso_sort_algorithm_dfs +- }; +- + struct audit_ifaces + { + void (*activity) (uintptr_t *, unsigned int); +@@ -640,8 +633,6 @@ struct rtld_global_ro + platforms. */ + EXTERN uint64_t _dl_hwcap2; + +- EXTERN enum dso_sort_algorithm _dl_dso_sort_algo; +- + #ifdef SHARED + /* We add a function table to _rtld_global which is then used to + call the function instead of going through the PLT. The result diff --git a/glibc.spec b/glibc.spec index 4c1e802..c1e7d19 100644 --- a/glibc.spec +++ b/glibc.spec @@ -1,7 +1,6 @@ -%define anolis_release .0.3 %define glibcsrcdir glibc-2.28 %define glibcversion 2.28 -%define glibcrelease 189.5%{anolis_release}%{?dist} +%define glibcrelease 225%{?dist} # Pre-release tarballs are pulled in from git using a command that is # effectively: # @@ -856,17 +855,30 @@ Patch660: glibc-rh2045063-2.patch Patch661: glibc-rh2045063-3.patch Patch662: glibc-rh2045063-4.patch Patch663: glibc-rh2045063-5.patch -Patch664: glibc-rh2061727.patch -Patch665: glibc-rh2073432.patch -Patch666: glibc-rh2084564.patch -Patch667: glibc-rh2094540.patch -Patch668: glibc-rh2093457-1.patch -Patch669: glibc-rh2093457-2.patch -Patch670: glibc-rh2093457-3.patch -Patch671: glibc-rh2093457-4.patch -Patch672: glibc-rh2093457-5.patch -Patch673: glibc-rh2093457-6.patch - +Patch664: glibc-rh2054790.patch +Patch665: glibc-rh2037416-1.patch +Patch666: glibc-rh2037416-2.patch +Patch667: glibc-rh2037416-3.patch +Patch668: glibc-rh2037416-4.patch +Patch669: glibc-rh2037416-5.patch +Patch670: glibc-rh2037416-6.patch +Patch671: glibc-rh2037416-7.patch +Patch672: glibc-rh2037416-8.patch +Patch673: glibc-rh2033684-1.patch +Patch674: glibc-rh2033684-2.patch +Patch675: glibc-rh2033684-3.patch +Patch676: glibc-rh2033684-4.patch +Patch677: glibc-rh2033684-5.patch +Patch678: glibc-rh2033684-6.patch +Patch679: glibc-rh2033684-7.patch +Patch680: glibc-rh2033684-8.patch +Patch681: glibc-rh2033684-9.patch +Patch682: glibc-rh2033684-10.patch +Patch683: glibc-rh2033684-11.patch +Patch684: glibc-rh2033684-12.patch +Patch685: glibc-rh2063712.patch +Patch686: glibc-rh2063042.patch +Patch687: glibc-rh2071745.patch Patch688: glibc-rh2065588-1.patch Patch689: glibc-rh2065588-2.patch Patch690: glibc-rh2065588-3.patch @@ -880,15 +892,145 @@ Patch697: glibc-rh2065588-10.patch Patch698: glibc-rh2065588-11.patch Patch699: glibc-rh2065588-12.patch Patch700: glibc-rh2065588-13.patch -Patch701: glibc-bz29016.patch - -Patch1000: glibc-Properly-check-stack-alignment-BZ-27901.patch -Patch1001: glibc-elf-Properly-align-PT_LOAD-segments-BZ-28676-1.patch -Patch1002: glibc-Add-a-testcase-to-check-alignment-of-PT_LOAD-segment-2.patch -Patch1003: glibc-elf-Align-argument-of-__munmap-to-page-size-BZ-28676-3.patch -Patch1004: glibc-Support-target-specific-ALIGN-for-variable-alignment-4.patch -Patch1005: glibc-elf-Fix-tst-align3.patch -Patch1006: glibc-LoongArch-Port.patch +Patch701: glibc-rh2072329.patch +Patch702: glibc-rh1982608.patch +Patch703: glibc-rh1961109.patch +Patch704: glibc-rh2086853.patch +Patch705: glibc-rh2077835.patch +Patch706: glibc-rh2089247-1.patch +Patch707: glibc-rh2089247-2.patch +Patch708: glibc-rh2089247-3.patch +Patch709: glibc-rh2089247-4.patch +Patch710: glibc-rh2089247-5.patch +Patch711: glibc-rh2089247-6.patch +Patch712: glibc-rh2091553.patch +Patch713: glibc-rh1888660.patch +Patch714: glibc-rh2096189-1.patch +Patch715: glibc-rh2096189-2.patch +Patch716: glibc-rh2096189-3.patch +Patch717: glibc-rh2080349-1.patch +Patch718: glibc-rh2080349-2.patch +Patch719: glibc-rh2080349-3.patch +Patch720: glibc-rh2080349-4.patch +Patch721: glibc-rh2080349-5.patch +Patch722: glibc-rh2080349-6.patch +Patch723: glibc-rh2080349-7.patch +Patch724: glibc-rh2080349-8.patch +Patch725: glibc-rh2080349-9.patch +Patch727: glibc-rh2047981-1.patch +Patch728: glibc-rh2047981-2.patch +Patch729: glibc-rh2047981-3.patch +Patch730: glibc-rh2047981-4.patch +Patch731: glibc-rh2047981-5.patch +Patch732: glibc-rh2047981-6.patch +Patch733: glibc-rh2047981-7.patch +Patch734: glibc-rh2047981-8.patch +Patch735: glibc-rh2047981-9.patch +Patch736: glibc-rh2047981-10.patch +Patch737: glibc-rh2047981-11.patch +Patch738: glibc-rh2047981-12.patch +Patch739: glibc-rh2047981-13.patch +Patch740: glibc-rh2047981-14.patch +Patch741: glibc-rh2047981-15.patch +Patch742: glibc-rh2047981-16.patch +Patch743: glibc-rh2047981-17.patch +Patch744: glibc-rh2047981-18.patch +Patch745: glibc-rh2047981-19.patch +Patch746: glibc-rh2047981-20.patch +Patch747: glibc-rh2047981-21.patch +Patch748: glibc-rh2047981-22.patch +Patch749: glibc-rh2047981-23.patch +Patch750: glibc-rh2047981-24.patch +Patch751: glibc-rh2047981-25.patch +Patch752: glibc-rh2047981-26.patch +Patch753: glibc-rh2047981-27.patch +Patch754: glibc-rh2047981-28.patch +Patch755: glibc-rh2047981-29.patch +Patch756: glibc-rh2047981-30.patch +Patch757: glibc-rh2047981-31.patch +Patch758: glibc-rh2047981-32.patch +Patch759: glibc-rh2047981-33.patch +Patch760: glibc-rh2047981-34.patch +Patch761: glibc-rh2047981-35.patch +Patch762: glibc-rh2047981-36.patch +Patch763: glibc-rh2047981-37.patch +Patch764: glibc-rh2047981-38.patch +Patch766: glibc-rh2047981-39.patch +Patch767: glibc-rh2047981-40.patch +Patch768: glibc-rh2047981-41.patch +Patch769: glibc-rh2047981-42.patch +Patch770: glibc-rh2047981-43.patch +Patch771: glibc-rh2047981-44.patch +Patch772: glibc-rh2047981-45.patch +Patch773: glibc-rh2047981-46.patch +Patch774: glibc-rh2047981-47.patch +Patch775: glibc-rh2104907.patch +Patch776: glibc-rh2119304-1.patch +Patch777: glibc-rh2119304-2.patch +Patch778: glibc-rh2119304-3.patch +Patch779: glibc-rh2118667.patch +Patch780: glibc-rh2122498.patch +Patch781: glibc-rh2125222.patch +Patch782: glibc-rh1871383-1.patch +Patch783: glibc-rh1871383-2.patch +Patch784: glibc-rh1871383-3.patch +Patch785: glibc-rh1871383-4.patch +Patch786: glibc-rh1871383-5.patch +Patch787: glibc-rh1871383-6.patch +Patch788: glibc-rh1871383-7.patch +Patch789: glibc-rh2122501-1.patch +Patch790: glibc-rh2122501-2.patch +Patch791: glibc-rh2122501-3.patch +Patch792: glibc-rh2122501-4.patch +Patch793: glibc-rh2122501-5.patch +Patch794: glibc-rh2121746-1.patch +Patch795: glibc-rh2121746-2.patch +Patch796: glibc-rh2116938.patch +Patch797: glibc-rh2109510-1.patch +Patch798: glibc-rh2109510-2.patch +Patch799: glibc-rh2109510-3.patch +Patch800: glibc-rh2109510-4.patch +Patch801: glibc-rh2109510-5.patch +Patch802: glibc-rh2109510-6.patch +Patch803: glibc-rh2109510-7.patch +Patch804: glibc-rh2109510-8.patch +Patch805: glibc-rh2109510-9.patch +Patch806: glibc-rh2109510-10.patch +Patch807: glibc-rh2109510-11.patch +Patch808: glibc-rh2109510-12.patch +Patch809: glibc-rh2109510-13.patch +Patch810: glibc-rh2109510-14.patch +Patch811: glibc-rh2109510-15.patch +Patch812: glibc-rh2109510-16.patch +Patch813: glibc-rh2109510-17.patch +Patch814: glibc-rh2109510-18.patch +Patch815: glibc-rh2109510-19.patch +Patch816: glibc-rh2109510-20.patch +Patch817: glibc-rh2109510-21.patch +Patch818: glibc-rh2109510-22.patch +Patch819: glibc-rh2109510-23.patch +Patch820: glibc-rh2139875-1.patch +Patch821: glibc-rh2139875-2.patch +Patch822: glibc-rh2139875-3.patch +Patch823: glibc-rh1159809-1.patch +Patch824: glibc-rh1159809-2.patch +Patch825: glibc-rh1159809-3.patch +Patch826: glibc-rh1159809-4.patch +Patch827: glibc-rh1159809-5.patch +Patch828: glibc-rh1159809-6.patch +Patch829: glibc-rh1159809-7.patch +Patch830: glibc-rh1159809-8.patch +Patch831: glibc-rh1159809-9.patch +Patch832: glibc-rh1159809-10.patch +Patch833: glibc-rh1159809-11.patch +Patch834: glibc-rh1159809-12.patch +Patch835: glibc-rh2141989.patch +Patch836: glibc-rh2142937-1.patch +Patch837: glibc-rh2142937-2.patch +Patch838: glibc-rh2142937-3.patch +Patch839: glibc-rh2144568.patch +Patch840: glibc-rh2154914-1.patch +Patch841: glibc-rh2154914-2.patch ############################################################################## # Continued list of core "glibc" package information: @@ -1780,6 +1922,20 @@ $olddir/build-%{target}/testrun.sh \ # default locale-archive without modification, and leaving compiled # locales as they are (without inclusion into the archive). cp locale-archive{,.tmpl} + +# Almost half the LC_CTYPE files in langpacks are identical to the C.utf8 +# variant which is installed by default. When we keep them as hardlinks, +# each langpack ends up retaining a copy. If we convert these to symbolic +# links instead, we save ~350K each when they get installed that way. +# +# LC_MEASUREMENT and LC_PAPER also have several duplicates but we don't +# bother with these because they are only ~30 bytes each. +pushd %{glibc_sysroot}/usr/lib/locale +for f in $(find eo *_* -samefile C.utf8/LC_CTYPE); do + rm $f && ln -s '../C.utf8/LC_CTYPE' $f +done +popd + # Create the file lists for the language specific sub-packages: for i in eo *_* do @@ -2088,7 +2244,7 @@ chmod 0444 master.filelist # - All the libnss files (we add back the ones we want later). # - All bench test binaries. # - The aux-cache, since it's handled specially in the files section. -# - The build-locale-archive binary since it's in the common package. +# - The build-locale-archive binary since it's in the all-langpacks package. # - Extra gconv modules. We add the required modules later. cat master.filelist \ | grep -v \ @@ -2213,13 +2369,15 @@ grep '%{_libdir}/lib.*\.a' < master.filelist \ ############################################################################### # All of the bin and certain sbin files go into the common package except -# iconvconfig which needs to go in glibc. Likewise nscd is excluded because +# iconvconfig which needs to go in glibc, and build-locale-archive which +# needs to go into glibc-all-langpacks. Likewise nscd is excluded because # it goes in nscd. The iconvconfig binary is kept in the main glibc package # because we use it in the post-install scriptlet to rebuild the # gconv-modules.cache. grep '%{_prefix}/bin' master.filelist >> common.filelist grep '%{_prefix}/sbin' master.filelist \ | grep -v '%{_prefix}/sbin/iconvconfig' \ + | grep -v '%{_prefix}/sbin/build-locale-archive' \ | grep -v 'nscd' >> common.filelist # All of the files under share go into the common package since they should be # multilib-independent. @@ -2235,9 +2393,6 @@ grep '%{_prefix}/share' master.filelist \ -e '%{_docdir}' \ >> common.filelist -# Add the binary to build locales to the common subpackage. -echo '%{_prefix}/sbin/build-locale-archive' >> common.filelist - ############################################################################### # nscd ############################################################################### @@ -2647,6 +2802,8 @@ fi %files all-langpacks %attr(0644,root,root) %verify(not md5 size mtime) %{_prefix}/lib/locale/locale-archive.tmpl %attr(0644,root,root) %verify(not md5 size mtime mode) %ghost %{_prefix}/lib/locale/locale-archive +# build-locale-archive re-generates locale-archive during install/upgrade/downgrade +%attr(0700,root,root) %{_prefix}/sbin/build-locale-archive %files locale-source %dir %{_prefix}/share/i18n/locales @@ -2704,30 +2861,120 @@ fi %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog -* Sat May 6 2023 Sinan Lin - 2.28-189.5.0.3 -- Fix popen set incorrect errno issue (#BZ 29016) -- Fix multi-threaded popen race condition issue (#2065588) +* Fri Jan 20 2023 Florian Weimer - 2.28-225 +- Enforce a specififc internal ordering for tunables (#2154914) -* Thu Jun 23 2022 wanghongliang - 2.28-189.5.0.2 -- arch: LoongArch Port +* Wed Nov 30 2022 Arjun Shankar - 2.28-224 +- Fix rtld-audit trampoline for aarch64 (#2144568) -* Fri Jun 17 2022 Rongwei Wang - 2.28-189.5.0.1 -- elf: Properly align PT_LOAD segments +* Fri Nov 25 2022 Arjun Shankar - 2.28-223 +- Backport upstream fixes to tst-pldd (#2142937) -* Wed Jun 8 2022 Florian Weimer - 2.28-189.5 -- Increase tempnam randomness (#2093457) +* Tue Nov 22 2022 Florian Weimer - 2.28-222 +- Restore IPC_64 support in sysvipc *ctl functions (#2141989) -* Tue Jun 07 2022 DJ Delorie - 2.28-189.4 -- Fix incorrect strncpy results on POWER9 (#2094540) +* Fri Nov 18 2022 Florian Weimer - 2.28-221 +- Switch to fast DSO dependency sorting algorithm (#1159809) -* Fri May 13 2022 Arjun Shankar - 2.28-189.3 -- Add missing MACRON to EBCDIC character sets (#2084564) +* Thu Nov 3 2022 Florian Weimer - 2.28-220 +- Explicitly switch to --with-default-link=no (#2109510) +- Define MAP_SYNC on ppc64le (#2139875) -* Fri May 13 2022 Arjun Shankar - 2.28-189.2 -- timezone: Fix a test that causes occasional build failure (#2073432) +* Mon Oct 24 2022 Arjun Shankar - 2.28-219 +- Fix -Wstrict-overflow warning when using CMSG_NXTHDR macro (#2116938) -* Thu Mar 10 2022 Florian Weimer - 2.28-189.1 -- nss: Avoid clobbering errno in get*ent via dlopen (#2061727) +* Fri Oct 14 2022 DJ Delorie - 2.28-218 +- Fix dlmopen/dlclose/dlmopen sequence and libc initialization (#2121746) + +* Thu Oct 13 2022 Arjun Shankar - 2.28-217 +- Fix memory corruption in printf with thousands separators and large + integer width (#2122501) + +* Wed Oct 05 2022 Arjun Shankar - 2.28-216 +- Retain .gnu_debuglink section for libc.so.6 (#2115830) +- Remove .annobin* symbols from ld.so +- Remove redundant ld.so debuginfo file + +* Wed Sep 28 2022 DJ Delorie - 2.28-215 +- Improve malloc implementation (#1871383) + +* Tue Sep 20 2022 Florian Weimer - 2.28-214 +- Fix hwcaps search path size computation (#2125222) + +* Tue Sep 20 2022 Florian Weimer - 2.28-213 +- Fix nscd netlink cache invalidation if epoll is used (#2122498) + +* Tue Sep 20 2022 Florian Weimer - 2.28-212 +- Run tst-audit-tlsdesc, tst-audit-tlsdesc-dlopen everywhere (#2118667) + +* Thu Aug 25 2022 Florian Weimer - 2.28-211 +- Preserve GLRO (dl_naudit) internal ABI (#2119304) +- Avoid s390x ABI change due to z16 recognition on s390x (#2119304) + +* Tue Aug 23 2022 Arjun Shankar - 2.28-210 +- Fix locale en_US@ampm (#2104907) + +* Fri Jul 22 2022 Carlos O'Donell - 2.28-209 +- Improve dynamic loader auditing interface (LD_AUDIT) (#2047981) +- Add dlinfo() API support for RTLD_DI_PHDR (#2097898) + +* Fri Jul 15 2022 Patsy Griffin - 2.28-208 +- Update syscall-names.list to Linux 5.18. (#2080349) + +* Fri Jun 24 2022 Florian Weimer - 2.28-207 +- Add the no-aaaa DNS stub resolver option (#2096189) + +* Thu Jun 9 2022 Arjun Shankar - 2.28-206 +- Fix deadlocks in pthread_atfork handlers (#1888660) + +* Tue Jun 07 2022 DJ Delorie - 2.28-204 +- Increase tempnam randomness (#2089247) + +* Tue May 17 2022 Patsy Griffin - 2.28-203 +- 390x: Add support for IBM z16. (#2077835) + +* Mon May 16 2022 Siddhesh Poyarekar - 2.28-202 +- Ensure that condition in __glibc_fortify is a constant (#2086853) + +* Tue May 10 2022 Arjun Shankar - 2.28-201 +- Add missing MACRON to EBCDIC character sets (#1961109) + +* Wed May 4 2022 DJ Delorie - 2.28-200 +- Fix glob defects on certain XFS filesystems (#1982608) + +* Tue Apr 26 2022 Siddhesh Poyarekar - 2.28-199 +- Fix fortify false positive with mbsrtowcs and mbsnrtowcs (#2072329). + +* Fri Apr 22 2022 Carlos O'Donell - 2.28-198 +- Fix multi-threaded popen defect leading to segfault (#2065588) + +* Tue Apr 05 2022 Arjun Shankar - 2.28-197 +- timezone: Fix a test that causes occasional build failure (#2071745) + +* Tue Mar 15 2022 Siddhesh Poyarekar 2.28-196 +- Synchronize feature guards in fortified functions (#2063042) + +* Mon Mar 14 2022 Florian Weimer - 2.28-195 +- nss: Avoid clobbering errno in get*ent via dlopen (#2063712) + +* Fri Mar 11 2022 Siddhesh Poyarekar 2.28-194 +- Enable support for _FORTIFY_SOURCE=3 for gcc 12 and later (#2033684) + +* Wed Mar 9 2022 DJ Delorie - 2.28-193 +- memory operation A64FX SVE performance improvement (#2037416) + +* Mon Mar 07 2022 Arjun Shankar - 2.28-192 +- Move build-locale-archive to glibc-all-langpacks (#2057513) + +* Mon Mar 07 2022 Arjun Shankar - 2.28-191 +- Fix build-locale-archive to handle symbolic links (#2054790) + +* Fri Mar 04 2022 Arjun Shankar - 2.28-190 +- Reduce installed size of some langpacks by de-duplicating LC_CTYPE (#2054790) +- Fix localedef so it can handle symbolic links when generating locale-archive. * Thu Jan 27 2022 Siddhesh Poyarekar - 2.28-189 - CVE-2021-3999: getcwd: align stack on clone in aarch64 and fix a memory leak diff --git a/wrap-find-debuginfo.sh b/wrap-find-debuginfo.sh index 6eeb802..8479217 100755 --- a/wrap-find-debuginfo.sh +++ b/wrap-find-debuginfo.sh @@ -17,6 +17,8 @@ set -evx tar_tmp="$(mktemp)" +declare -A libc_dlink_tmp_list +ldso_annobin_sym_tmp_list="" # Prefer a separately installed debugedit over the RPM-integrated one. if command -v debugedit >/dev/null ; then @@ -26,7 +28,7 @@ else fi cleanup () { - rm -f "$tar_tmp" + rm -f "$tar_tmp" ${libc_dlink_tmp_list[@]} $ldso_annobin_sym_tmp_list } trap cleanup 0 @@ -51,6 +53,15 @@ full_list="$ldso_list $libc_list $libdl_list $libpthread_list $librt_list" # Run the debuginfo extraction. "$script_path" "$@" +# libc.so.6: Extract the .gnu_debuglink section +for f in $libc_list +do + dlink_tmp="$(mktemp)" + libc_dlink_tmp_list["$f"]="$dlink_tmp" + objcopy -j.gnu_debuglink --set-section-flags .gnu_debuglink=alloc \ + -O binary "$sysroot_path/$f" "$dlink_tmp" +done + # Restore the original files. (cd "$sysroot_path"; tar xf "$tar_tmp") (cd "$sysroot_path"; ls -l $full_list) @@ -61,6 +72,20 @@ do objcopy --merge-notes "$sysroot_path/$p" done +# libc.so.6: Restore the .gnu_debuglink section +for f in ${!libc_dlink_tmp_list[@]} +do + dlink_tmp="${libc_dlink_tmp_list[$f]}" + objcopy --add-section .gnu_debuglink="$dlink_tmp" "$sysroot_path/$f" +done + +# ld.so does not have separated debuginfo and so the debuginfo file +# generated by find-debuginfo is redundant. Therefore, remove it. +for ldso_debug in `find "$sysroot_path" -name 'ld-*.so*.debug' -type f` +do + rm -f "$ldso_debug" +done + # libc.so.6 and other shared objects: Reduce to valuable symbols. # Eliminate file symbols, annobin symbols, and symbols used by the # glibc build to implement hidden aliases (__EI_*). We would also @@ -103,6 +128,14 @@ debug_base_name=${last_arg:-$RPM_BUILD_ROOT} for p in $ldso_list do $debugedit -b "$debug_base_name" -d "$debug_dest_name" -n "$sysroot_path/$p" + + # Remove the .annobin* symbols (and only them). + ldso_annobin_sym_tmp="$(mktemp)" + ldso_annobin_sym_tmp_list+=" $ldso_annobin_sym_tmp" + if nm --format=posix "$sysroot_path/$p" | cut -d' ' -f1 \ + | grep '^\.annobin' > "$ldso_annobin_sym_tmp"; then + objcopy --strip-symbols="$ldso_annobin_sym_tmp" "$sysroot_path/$p" + fi done # Apply single-file DWARF optimization.